ftp(1): tls_close(3) handle TLS_WANT_POLLIN, TLS_WANT_PLLOUT
Hi, tls_close() could return TLS_WANT_POLLIN, TLS_WANT_POLLOUT as well. This diff repeats the call immediately. Ok? cvs server: Diffing . Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.161 diff -u -p -r1.161 fetch.c --- fetch.c 28 Feb 2017 06:31:12 - 1.161 +++ fetch.c 2 Mar 2017 07:20:29 - @@ -1031,7 +1031,9 @@ improper: cleanup_url_get: #ifndef NOSSL if (tls != NULL) { - tls_close(tls); + do { + i = tls_close(tls); + } while (i == TLS_WANT_POLLIN || i == TLS_WANT_POLLOUT); tls_free(tls); } free(full_host);
Re: ftp doesn't close(2) the output file
Theo de Raadtwrites: >> > Index: fetch.c >> > === >> > RCS file: /cvs/src/usr.bin/ftp/fetch.c,v >> > retrieving revision 1.161 >> > diff -u -p -r1.161 fetch.c >> > --- fetch.c28 Feb 2017 06:31:12 - 1.161 >> > +++ fetch.c1 Mar 2017 23:21:46 - >> > @@ -1041,6 +1041,8 @@ cleanup_url_get: >> >fclose(fin); >> >else if (s != -1) >> >close(s); >> > + if (out >= 0 && out != fileno(stdout)) >> > + close(out); >> >free(buf); >> >free(proxyhost); >> >free(proxyurl); >> >> I was wondering if the "out >= 0" condition is necessary as open(2) >> errors are handled anyway. > > Sure, but it is cleaner to not call close(-1). oh right, the cleanup_url_get ends up here as well, and this condition is required. Sorry for the noise.
Re: ftp doesn't close(2) the output file
Stuart Hendersonwrites: > ftp doesn't close the output file after writing it. Normally you're > exiting anyway at that point so it doesn't really matter, but if you've > specified multiple URLs on the command line this leaks 1 FD per > requested file. Most noticable if you do some lazy benchark like > "ftp -o/dev/null `yes $SOMEURL | head -1000`" and run yourself out > of FDs. > > Possible fix? > > Index: fetch.c > === > RCS file: /cvs/src/usr.bin/ftp/fetch.c,v > retrieving revision 1.161 > diff -u -p -r1.161 fetch.c > --- fetch.c 28 Feb 2017 06:31:12 - 1.161 > +++ fetch.c 1 Mar 2017 23:21:46 - > @@ -1041,6 +1041,8 @@ cleanup_url_get: > fclose(fin); > else if (s != -1) > close(s); > + if (out >= 0 && out != fileno(stdout)) > + close(out); > free(buf); > free(proxyhost); > free(proxyurl); I was wondering if the "out >= 0" condition is necessary as open(2) errors are handled anyway.
Re: smtpd: more internal cleanups
Eric Faurot writes: > Hi. > > When using the internal io api, the caller had to explicitely reset an > io event in some cases (basically when data is buffered outside of an > io callback context) which could easily be missed. This has been the > cause of some of smtpd bugs in the past (hanging sessions). > > After the recent changes, it's now possible to make it a lot simpler > by triggering an event reload internally when data is queued. So the > api user does not have to worry about it. > > Eric. Ok sunil@ > > Index: ioev.c > === > RCS file: /cvs/src/usr.sbin/smtpd/ioev.c,v > retrieving revision 1.31 > diff -u -p -r1.31 ioev.c > --- ioev.c22 Nov 2016 07:28:42 - 1.31 > +++ ioev.c22 Nov 2016 22:24:25 - > @@ -370,13 +370,25 @@ io_set_write(struct io *io) > int > io_write(struct io *io, const void *buf, size_t len) > { > - return iobuf_queue(io->iobuf, buf, len); > + int r; > + > + r = iobuf_queue(io->iobuf, buf, len); > + > + io_reload(io); > + > + return r; > } > > int > io_writev(struct io *io, const struct iovec *iov, int iovcount) > { > - return iobuf_queuev(io->iobuf, iov, iovcount); > + int r; > + > + r = iobuf_queuev(io->iobuf, iov, iovcount); > + > + io_reload(io); > + > + return r; > } > > int > Index: mta_session.c > === > RCS file: /cvs/src/usr.sbin/smtpd/mta_session.c,v > retrieving revision 1.89 > diff -u -p -r1.89 mta_session.c > --- mta_session.c 22 Nov 2016 07:28:42 - 1.89 > +++ mta_session.c 22 Nov 2016 22:24:26 - > @@ -280,7 +280,6 @@ mta_session_imsg(struct mproc *p, struct > mta_flush_task(s, IMSG_MTA_DELIVERY_TEMPFAIL, > "Could not get message fd", 0, 0); > mta_enter_state(s, MTA_READY); > - io_reload(>io); > return; > } > > @@ -289,7 +288,6 @@ mta_session_imsg(struct mproc *p, struct > fatal("mta: fdopen"); > > mta_enter_state(s, MTA_MAIL); > - io_reload(>io); > return; > > case IMSG_MTA_DNS_PTR: > @@ -366,7 +364,6 @@ mta_session_imsg(struct mproc *p, struct > > mta_tls_verified(s); > io_resume(>io, IO_PAUSE_IN); > - io_reload(>io); > return; > > case IMSG_MTA_LOOKUP_HELO: > @@ -456,7 +453,6 @@ mta_on_timeout(struct runq *runq, void * > s->hangon++; > > mta_enter_state(s, MTA_READY); > - io_reload(>io); > } > > static void > Index: smtp_session.c > === > RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v > retrieving revision 1.295 > diff -u -p -r1.295 smtp_session.c > --- smtp_session.c22 Nov 2016 07:28:42 - 1.295 > +++ smtp_session.c22 Nov 2016 22:24:26 - > @@ -738,14 +738,12 @@ smtp_session_imsg(struct mproc *p, struc > smtp_filter_tx_rollback(s); > smtp_tx_free(s->tx); > smtp_reply(s, "%d %s", 530, "Sender rejected"); > - io_reload(>io); > break; > case LKA_TEMPFAIL: > smtp_filter_tx_rollback(s); > smtp_tx_free(s->tx); > smtp_reply(s, "421 %s: Temporary Error", > esc_code(ESC_STATUS_TEMPFAIL, > ESC_OTHER_MAIL_SYSTEM_STATUS)); > - io_reload(>io); > break; > } > return; > @@ -766,7 +764,6 @@ smtp_session_imsg(struct mproc *p, struc > case LKA_TEMPFAIL: > smtp_reply(s, "%s", line); > } > - io_reload(>io); > return; > > case IMSG_SMTP_LOOKUP_HELO: > @@ -802,7 +799,6 @@ smtp_session_imsg(struct mproc *p, struc > smtp_enter_state(s, STATE_QUIT); > } > m_end(); > - io_reload(>io); > return; > > case IMSG_SMTP_MESSAGE_OPEN: > @@ -818,7 +814,6 @@ smtp_session_imsg(struct mproc *p, struc > smtp_reply(s, "421 %s: Temporary Error", > esc_code(ESC_STATUS_TEMPFAIL, > ESC_OTHER_MAIL_SYSTEM_STATUS)); > smtp_enter_state(s, STATE_QUIT); > - io_reload(>io); > return; > } > > @@ -872,7 +867,6 @@ smtp_session_imsg(struct mproc *p, struc > esc_code(ESC_STATUS_OK, > ESC_DESTINATION_ADDRESS_VALID), > esc_description(ESC_DESTINATION_ADDRESS_VALID)); > } > - io_reload(>io); > return; > > case IMSG_SMTP_MESSAGE_COMMIT: > @@ -887,7 +881,6 @@
Re: smtpd: simplify internal io api
Eric Faurot writes: > The api user should not have to care about normalizing the io input > buffer (i.e. resetting the read/write pos in the buffer). > Do it internally when reloading the io event. > > Eric. Ok sunil@ > > Index: bounce.c > === > RCS file: /cvs/src/usr.sbin/smtpd/bounce.c,v > retrieving revision 1.75 > diff -u -p -r1.75 bounce.c > --- bounce.c 21 Nov 2016 13:00:43 - 1.75 > +++ bounce.c 21 Nov 2016 19:33:46 - > @@ -728,10 +728,8 @@ bounce_io(struct io *io, int evt, void * > return; > } > > - if (line == NULL) { > - iobuf_normalize(>iobuf); > + if (line == NULL) > break; > - } > > log_trace(TRACE_BOUNCE, "bounce: %p: <<< %s", s, line); > > Index: filter.c > === > RCS file: /cvs/src/usr.sbin/smtpd/filter.c,v > retrieving revision 1.22 > diff -u -p -r1.22 filter.c > --- filter.c 21 Nov 2016 13:00:43 - 1.22 > +++ filter.c 21 Nov 2016 19:33:46 - > @@ -706,7 +706,6 @@ filter_tx_io(struct io *io, int evt, voi > } > s->idatalen += n; > io_drop(>iev, n); > - iobuf_normalize(>ibuf); > return; > > case IO_DISCONNECTED: > Index: ioev.c > === > RCS file: /cvs/src/usr.sbin/smtpd/ioev.c,v > retrieving revision 1.30 > diff -u -p -r1.30 ioev.c > --- ioev.c20 Nov 2016 08:43:36 - 1.30 > +++ ioev.c21 Nov 2016 19:33:46 - > @@ -465,6 +465,9 @@ io_reload(struct io *io) > if (io->flags & IO_HELD) > return; > > + if (io->iobuf) > + iobuf_normalize(io->iobuf); > + > #ifdef IO_SSL > if (io->ssl) { > io_reload_ssl(io); > Index: mta_session.c > === > RCS file: /cvs/src/usr.sbin/smtpd/mta_session.c,v > retrieving revision 1.88 > diff -u -p -r1.88 mta_session.c > --- mta_session.c 21 Nov 2016 13:00:43 - 1.88 > +++ mta_session.c 21 Nov 2016 19:33:47 - > @@ -1182,10 +1182,8 @@ mta_io(struct io *io, int evt, void *arg > if (io_datalen(>io) >= LINE_MAX) { > mta_error(s, "Input too long"); > mta_free(s); > - return; > } > - iobuf_normalize(>iobuf); > - break; > + return; > } > > log_trace(TRACE_MTA, "mta: %p: <<< %s", s, line); > @@ -1263,8 +1261,6 @@ mta_io(struct io *io, int evt, void *arg > mta_connect(s); > return; > } > - > - iobuf_normalize(>iobuf); > > if (io_datalen(>io)) { > log_debug("debug: mta: remaining data in input buffer"); > Index: smtp_session.c > === > RCS file: /cvs/src/usr.sbin/smtpd/smtp_session.c,v > retrieving revision 1.294 > diff -u -p -r1.294 smtp_session.c > --- smtp_session.c21 Nov 2016 13:00:43 - 1.294 > +++ smtp_session.c21 Nov 2016 19:33:48 - > @@ -1310,10 +1310,8 @@ smtp_io(struct io *io, int evt, void *ar > } > > /* No complete line received */ > - if (line == NULL) { > - iobuf_normalize(>iobuf); > + if (line == NULL) > return; > - } > > /* Message body */ > if (s->state == STATE_BODY && strcmp(line, ".")) { > @@ -1338,7 +1336,6 @@ smtp_io(struct io *io, int evt, void *ar > > rfc2822_parser_flush(>tx->rfc2822_parser); > > - iobuf_normalize(>iobuf); > io_set_write(io); > > s->tx->dataeom = 1; > @@ -1353,7 +1350,6 @@ smtp_io(struct io *io, int evt, void *ar > (void)strlcpy(s->cmd, line, sizeof s->cmd); > io_set_write(io); > smtp_command(s, line); > - iobuf_normalize(>iobuf); > break; > > case IO_LOWAT:
Re: mg: Collect forked off children from M-| command
On Wed, Sep 07, 2016 at 12:05:22PM +, Mark Lumsden wrote: > Source Joachim Nilsson: > > Collect forked off children from M-| command > > Mg left zombies from commands executed when piping a region of text to > an external command. This patch makes sure to collect for the child > before returning. > > Looks ok to me. ok? Ok sunil@
Re: Another step in cleaning the smtpd exit path.
On Sun, Sep 04, 2016 at 05:02:07PM +0200, Eric Faurot wrote: > > The smtpd processes are not expected to ever leave their event loop. > So stop pretending that the *_shutdown() functions could ever be called > in this context, and just fatal() if event_dispatch() returns. > > Eric. Ok sunil@
Re: [patch] mg: Prevent out-of-bounds read when PATH="/:..."
> On Tue, Jan 19, 2016 at 12:35:27PM +0100, Sunil Nimmagadda wrote: > > > > - dlen = strlen(dir); > > > - while (dir[dlen-1] == '/') > > > - dir[--dlen] = '\0'; /* strip trailing '/' */ > > > dlen could never be zero as we are replacing dir[0] with '.' if > > it's an empty field but that has another problem of wrong strlen(3) > > values due to improper NUL termination. The simple fix is to skip > > empty fields in PATH which I committed. > > Actually, the problem my diff was supposed to address is not empty > fields, but fields containing a slash and nothing else. Then, > dir[0] == '/' and dir[1] == '\0', so dlen == 1, and the while-loop > quoted above runs, and *decrements dlen* to 0. Then, to check if the > loop condition is still true, the program reads dir[-1]. If the > slash-only field is at the beginning of the path (e.g., > PATH = "/:/bin:...") this means reading path[-1]. ah right, sorry, I misread your diff. Ok to commit? Index: cscope.c === RCS file: /cvs/src/usr.bin/mg/cscope.c,v retrieving revision 1.15 diff -u -p -r1.15 cscope.c --- cscope.c19 Jan 2016 11:39:06 - 1.15 +++ cscope.c19 Jan 2016 13:38:06 - @@ -614,7 +614,7 @@ csexists(const char *cmd) continue; dlen = strlen(dir); - while (dir[dlen-1] == '/') + while (dlen > 0 && dir[dlen-1] == '/') dir[--dlen] = '\0'; /* strip trailing '/' */ len = snprintf(fname, sizeof(fname), "%s/%s", dir, cmd);
Re: makemap call in etc/mail/Makefile
> Hi OpenBSD devs, > > there is no more makemap[1]. > > [1]: http://www.openbsd.org/faq/current.html#20151207 That is smtpd(8)'s internal implementation of makemap as a seperate executable that got merged and not /usr/sbin/makemap. makemap(8) still exists and mailwrapper(8) would call an appropriate executable configured in mailer.conf which by default now is smtpctl(8). Also, aliases.db is required for the default smtpd.conf(5) and cannot be removed. > > Index: etc/mail/Makefile > === > RCS file: /cvs/src/etc/mail/Makefile,v > retrieving revision 1.12 > diff -u -p -u -p -r1.12 Makefile > --- etc/mail/Makefile 8 Dec 2015 09:03:50 - 1.12 > +++ etc/mail/Makefile 19 Dec 2015 10:47:51 - > @@ -3,7 +3,6 @@ > # Generate the various .db versions from their source files. > > DB_FILES= aliases.db > -MAKEMAP= /usr/sbin/makemap > > all: ${DB_FILES} > > @@ -12,8 +11,6 @@ clean: > > distribution: > ${INSTALL} -c -o root -g wheel -m 644 aliases \ > - ${DESTDIR}/etc/mail/aliases > - ${MAKEMAP} -t aliases -o ${DESTDIR}/etc/mail/aliases.db \ > ${DESTDIR}/etc/mail/aliases > ${INSTALL} -c -o root -g wheel -m 644 smtpd.conf \ > ${DESTDIR}/etc/mail/smtpd.conf >
Re: [patch] mailwrapper: remove broken fallback code
> If /etc/mailer.conf doesn't exist, mailwrapper tries to run sendmail, > giving a confusing error message: > > mailwrapper: cannot exec /usr/libexec/sendmail/sendmail: No such > file or directory > > This patch removes this fallback code. I believe this is cleaner than > updating the fallback since we would have to put two paths in: one for > sendmail/send-mail/mailq and one for makemap/newaliases. I am not sure about removing the fallback code but if we decide to keep it, this diff should fix the fallback case. Index: mailwrapper.c === RCS file: /cvs/src/usr.sbin/mailwrapper/mailwrapper.c,v retrieving revision 1.20 diff -u -p -r1.20 mailwrapper.c --- mailwrapper.c 12 Oct 2015 22:01:08 - 1.20 +++ mailwrapper.c 8 Dec 2015 09:36:18 - @@ -41,7 +41,7 @@ #include #define _PATH_MAILERCONF "/etc/mailer.conf" -#define _PATH_DEFAULTMTA "/usr/libexec/sendmail/sendmail" +#define _PATH_DEFAULTMTA "/usr/sbin/smtpctl" struct arglist { size_t argc, maxc;
http(1) An alternate implementation for a subset of ftp(1)
Hi, http(1) is a drop-in substitute for ftp(1)'s AUTO-FETCHING FILES mode. It defaults to HTTP method when the url doesn't specify the protocol and supports transferring files from HTTP(S) and FTP servers. The FTP support is limited to file transfer and doesn't do command interpretation. It works[0] with pkg_add(1) and related tools when set as FETCH_CMD. A SMALL variant could be built by disabling FTP and HTTPS support. Source: http://www.nimmagadda.net/http.tar.gz Thanks Patrick Keshishian and sthen@ for spotting Host header bug in previous version. Comments/Suggestions to improve it are most welcome. [0] Needs this small pkg_add(1) diff to get rid of the error messages when fetching for a FTP server... http://marc.info/?l=openbsd-techm=143966672102753w=2
Re: http(1) An alternate implementation for a subset of ftp(1)
On Mon, Aug 17, 2015 at 06:06:17PM +0200, Sebastien Marie wrote: Hi, I start reading your code, and I have a first remark. I see in main.c (at line 142 and next) that on redirection, you trust the server for the filename. I am not sure it is a good thing to do. If the user request 'http://www.example.com/a_filename' (without -o), the file created should be 'a_filename' what ever the redirection is. Else, a evil server could arbitrary choose the filename (in the current directory), and as file creation is done with O_TRUNC (or O_APPEND in resume case), an evil server could override the file he wants. Thanks for the comments, I agree with your observation. This diff evaluates filename just once. Index: main.c === RCS file: /cvs/http/main.c,v retrieving revision 1.67 diff -u -p -r1.67 main.c --- main.c 16 Aug 2015 08:00:25 - 1.67 +++ main.c 17 Aug 2015 17:33:20 - @@ -108,8 +108,8 @@ main(int argc, char *argv[]) } for (i = 0; i argc; i++) { -retry: fn = (output) ? output : basename(argv[i]); +retry: url_str = url_encode(argv[i]); p = url_type(url_str); if (url_parse(url_str, url, p) != 0)
pkg_add: Adjust problem detection
Hi, 213 is a valid return code from an FTP server for SIZE command and should not be treated as a problem. Alternate implementations of FETCH_CMD could provide a slightly different Requesting url log lines. Would it be okay to relax the format a bit and ignore any line starting with Requesting instead. Index: OpenBSD/PackageRepository.pm === RCS file: /cvs/src/usr.sbin/pkg_add/OpenBSD/PackageRepository.pm,v retrieving revision 1.114 diff -u -p -r1.114 PackageRepository.pm --- OpenBSD/PackageRepository.pm12 Jul 2015 14:52:17 - 1.114 +++ OpenBSD/PackageRepository.pm15 Aug 2015 18:58:03 - @@ -666,10 +666,11 @@ sub parse_problems } my $notyet = 1; while($fh) { - next if m/^(?:200|220|221|226|229|230|227|250|331|500|150)[\s\-]/o; + next if m/^(?:150|200|213|220|221|226|229|230|227|250)[\s\-]/o; + next if m/^(?:331|500)[\s\-]/o; next if m/^EPSV command not understood/o; next if m/^Trying [\da-f\.\:]+\.\.\./o; - next if m/^Requesting \Q$baseurl\E/; + next if m/^Requesting/; next if m/^Remote system type is\s+/o; next if m/^Connected to\s+/o; next if m/^remote\:\s+/o;
Re: ftp(1) rewrite
On Thu, May 21, 2015 at 11:16:09PM -0400, Ted Unangst wrote: Sunil Nimmagadda wrote: Hi, The idea is to start with the subset of ftp(1) functionality needed by pkg_add(1): ftp [-o output] url ... i.e., should be able to download files over HTTP(S) and FTP. This implementation works as FETCH_CMD for pkg_add(1) over HTTP(S). FTP is not yet done, but thinking of implementing just PASV and RETR commands and drop command interpreter compeletely. The SMALL variant drops HTTPS and FTP support. Comments? screw ftp. just make a new util http, that just does http. Hi, Here is a work in progress version 2. Changes from previous diff... 1. Drop ftp provision and rename the utility as http(1). 2. HTTP redirect handling. 3. Proxy support. 4. Resume interrupted file transfer. 5. Basic and Proxy Authorization. Todo: progressmeter, cookies, RFC1738 URL encoding/decoding and maybe some more. Comments? Index: Makefile === RCS file: Makefile diff -N Makefile --- /dev/null 1 Jan 1970 00:00:00 - +++ Makefile1 Jun 2015 09:02:59 - @@ -0,0 +1,19 @@ +# Define SMALL to disable https support +.if defined(SMALL) +CFLAGS+= -DSMALL +.endif + +PROG= http +MAN= http.1 +DEBUG= -g -Wall -O0 +SRCS= main.c http.c +LDADD+=-lutil +DPADD+=${LIBUTIL} + +.ifndef SMALL +SRCS+= https.c +LDADD+=-ltls -lssl -lcrypto +DPADD+=${LIBTLS} ${LIBSSL} ${LIBCRYPTO} +.endif + +.include bsd.prog.mk Index: http.1 === RCS file: http.1 diff -N http.1 --- /dev/null 1 Jan 1970 00:00:00 - +++ http.1 1 Jun 2015 09:02:59 - @@ -0,0 +1,94 @@ +.\ Copyright (c) 1985, 1989, 1990, 1993 +.\The Regents of the University of California. All rights reserved. +.\ +.\ Redistribution and use in source and binary forms, with or without +.\ modification, are permitted provided that the following conditions +.\ are met: +.\ 1. Redistributions of source code must retain the above copyright +.\notice, this list of conditions and the following disclaimer. +.\ 2. Redistributions in binary form must reproduce the above copyright +.\notice, this list of conditions and the following disclaimer in the +.\documentation and/or other materials provided with the distribution. +.\ 3. Neither the name of the University nor the names of its contributors +.\may be used to endorse or promote products derived from this software +.\without specific prior written permission. +.\ +.\ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\ SUCH DAMAGE. +.\ +.\@(#)ftp.1 8.3 (Berkeley) 10/9/94 +.\ +.\ Copyright (c) 2015 Sunil Nimmagadda su...@nimmagadda.net +.\ +.\ Permission to use, copy, modify, and distribute this software for any +.\ purpose with or without fee is hereby granted, provided that the above +.\ copyright notice and this permission notice appear in all copies. +.\ +.\ THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\ +.Dd $Mdocdate: June 1 2015 $ +.Dt HTTP 1 +.Os +.Sh NAME +.Nm http +.Nd HTTP file transfer program +.Sh SYNOPSIS +.Nm +.Op Fl C +.Op Fl o Ar output +.Op Fl P Ar port +.Op Fl U Ar useragent +.Op Fl V +.Ar ... +.Sh DESCRIPTION +.Nm +allows a user to transfer files from a remote HTTP server. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl C +Continue a previously interrupted file transfer. +.Nm +will continue transferring from an offset equal to the length of file. +.Pp +Resuming HTTP(s) transfers are only supported +if the remote server supports the +.Dq Range +header. +.It Fl o Ar output +When fetching a single file or URL, save the contents in +.Ar output. +.It Fl P Ar port
ftp(1) rewrite
Hi, The idea is to start with the subset of ftp(1) functionality needed by pkg_add(1): ftp [-o output] url ... i.e., should be able to download files over HTTP(S) and FTP. This implementation works as FETCH_CMD for pkg_add(1) over HTTP(S). FTP is not yet done, but thinking of implementing just PASV and RETR commands and drop command interpreter compeletely. The SMALL variant drops HTTPS and FTP support. Comments? Note: A lot of functionality is still missing including proxy, redirects, progressmeter, UerAgent, Ranges, etc. Index: Makefile === RCS file: Makefile diff -N Makefile --- /dev/null 1 Jan 1970 00:00:00 - +++ Makefile21 May 2015 18:23:37 - @@ -0,0 +1,19 @@ +# Define SMALL to disable https and ftp support +.if defined(SMALL) +CFLAGS+= -DSMALL +.endif + +PROG= ftp +NOMAN= +DEBUG= -g -Wall -O0 +SRCS= main.c http.c +LDADD+=-lutil +DPADD+=${LIBUTIL} + +.ifndef SMALL +SRCS+= https.c ftp.c +LDADD+=-ltls -lssl -lcrypto +DPADD+=${LIBTLS} ${LIBSSL} ${LIBCRYPTO} +.endif + +.include bsd.prog.mk Index: ftp.c === RCS file: ftp.c diff -N ftp.c --- /dev/null 1 Jan 1970 00:00:00 - +++ ftp.c 21 May 2015 18:23:37 - @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 Sunil Nimmagadda su...@nimmagadda.net + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/types.h + +#include ftp.h + +intftp_connect(const char *, const char *); +intftp_get(int, const char *, const char *, int); + +struct proto proto_ftp = { + ftp_connect, + ftp_get +}; + +int +ftp_connect(const char *host, const char *port) +{ + return (-1); +} + +int +ftp_get(int s, const char *resource, const char *fn, int flags) +{ + return (-1); +} Index: ftp.h === RCS file: ftp.h diff -N ftp.h --- /dev/null 1 Jan 1970 00:00:00 - +++ ftp.h 21 May 2015 18:23:37 - @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 Sunil Nimmagadda su...@nimmagadda.net + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define BUF_SIZ1024 +#defineTMPBUF_LEN 131072 +#define MAX_RETRIES10 + +struct http_headers { + charlocation[BUF_SIZ]; /* Redirect Location */ + off_t c_len; /* Content-Length */ +}; + +struct proto { + int (*connect)(const char *, const char *); + int (*get)(int, const char *, const char *, int); +}; + +/* main.c */ +inthost_extract(char *, char *, size_t); +intheader_insert(struct http_headers *, const char *); + +/* http.c */ +inthttp_connect(const char *, const char *); +inthttp_response_code(char *); + Index: http.c === RCS file: http.c diff -N http.c --- /dev/null 1 Jan 1970 00:00:00 - +++ http.c 21 May 2015 18:23:37 - @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2015 Sunil Nimmagadda su...@nimmagadda.net + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL
Re: Byte range implementation for httpd(8)
On Sat, May 02, 2015 at 02:49:30PM +, Florian Obser wrote: Sorry for the very late reply, I'm currently very busy :/ Thank you for taking time to review it. A new patch with style nits fixed and a gratuitous NULL check removed. [trimming some text] this is missing the server_file_method() song and dance from server_file_request() Fixed in a slightly different way than using server_file_method(). Since range request should be ignored for methods other than GET, fallback to server_file_request() for further processing/validation. + if ((range = parse_range(range_str, st-st_size, nranges)) == NULL) { + code = 416; + (void)snprintf(content_range, sizeof(content_range), + bytes */%lld, st-st_size); + errstr = content_range; + goto abort; + } hm, apache answers with the full file and 200 if the range header is syntactically incorrect or if end start. As far as I can tell it only answers 416 if the range actually lies outside of the file. I am confused about the RFC here, section 4.4 states that 416 is returned if ...the set of ranges requested has been rejected due to invalid ranges... and a note follows immediately, Because servers are free to ignore Range, many implementations will simply respond with the entire selected representation in a 200 response As you noted apache returns 200 while nginx returns 416 for an incorrect range. What should httpd do ideally? + + /* Accept byte ranges */ + if (code == 200 + kv_add(resp-http_headers, Accept-Ranges, bytes) == NULL) return (-1); I don't think we should advertise ranges for all 200 results, for example we don't support it for directory indexes. Agree, since RFC says server MAY send Accept-Range header and clients MAY generate range requests without having received this header field, dropping this header shouldn't make a difference. Comments? Index: server_file.c === RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v retrieving revision 1.52 diff -u -p -r1.52 server_file.c --- server_file.c 25 Apr 2015 14:40:35 - 1.52 +++ server_file.c 3 May 2015 11:18:07 - @@ -36,12 +36,25 @@ #define MINIMUM(a, b) (((a) (b)) ? (a) : (b)) #define MAXIMUM(a, b) (((a) (b)) ? (a) : (b)) +#define MAX_RANGES 4 -int server_file_access(struct httpd *, struct client *, char *, size_t); -int server_file_request(struct httpd *, struct client *, char *, - struct stat *); -int server_file_index(struct httpd *, struct client *, struct stat *); -int server_file_method(struct client *); +struct range { + off_t start; + off_t end; +}; + +int server_file_access(struct httpd *, struct client *, + char *, size_t); +int server_file_request(struct httpd *, struct client *, + char *, struct stat *); +int server_partial_file_request(struct httpd *, struct client *, + char *, struct stat *, char *); +int server_file_index(struct httpd *, struct client *, + struct stat *); +int server_file_method(struct client *); +int parse_range_spec(char *, size_t, struct range *); +struct range *parse_range(char *, size_t, int *); +int buffer_add_range(int, struct evbuffer *, struct range *); int server_file_access(struct httpd *env, struct client *clt, @@ -50,6 +63,7 @@ server_file_access(struct httpd *env, st struct http_descriptor *desc = clt-clt_descreq; struct server_config*srv_conf = clt-clt_srv_conf; struct stat st; + struct kv *r, key; char*newpath; int ret; @@ -123,7 +137,13 @@ server_file_access(struct httpd *env, st goto fail; } - return (server_file_request(env, clt, path, st)); + key.kv_key = Range; + r = kv_find(desc-http_headers, key); + if (r != NULL) + return (server_partial_file_request(env, clt, path, st, + r-kv_value)); + else + return (server_file_request(env, clt, path, st)); fail: switch (errno) { @@ -262,6 +282,143 @@ server_file_request(struct httpd *env, s } int +server_partial_file_request(struct httpd *env, struct client *clt, char *path, +struct stat *st, char *range_str) +{ + struct http_descriptor *resp = clt-clt_descresp; + struct http_descriptor *desc = clt-clt_descreq; + struct media_type *media, multipart_media; + struct range*range; + struct evbuffer *evb = NULL; + size_t content_length; + int code = 500, fd = -1, i, nranges, ret; + uint32_t boundary; + char
Re: Byte range implementation for httpd(8)
Any interest/comments/suggestions for this diff... On Fri, Apr 17, 2015 at 05:04:01AM +0200, Sunil Nimmagadda wrote: Range requests as defined in RFC7233 is required for resuming interrupted http(s) downloads for example: ftp -C http://foo.bar/install57.iso With this diff, httpd parses Range header in the requests and provide either 206(Partial Content) or 416(Range not Satisfiable) responses with Content-Range header set appropriately. Further, it understands multi range request and generate satisfiable payloads with multipart/byteranges media type. Suggestions/comments to improve the diff are welcome. Note, If-Range isn't implemented yet. Index: server_file.c === RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v retrieving revision 1.51 diff -u -p -r1.51 server_file.c --- server_file.c 12 Feb 2015 10:05:29 - 1.51 +++ server_file.c 17 Apr 2015 02:22:12 - @@ -36,12 +36,23 @@ #define MINIMUM(a, b)(((a) (b)) ? (a) : (b)) #define MAXIMUM(a, b)(((a) (b)) ? (a) : (b)) +#define MAX_RANGES 4 + +struct range { + off_t start; + off_t end; +}; int server_file_access(struct httpd *, struct client *, char *, size_t); int server_file_request(struct httpd *, struct client *, char *, struct stat *); +int server_partial_file_request(struct httpd *, struct client *, char *, + struct stat *, char *); int server_file_index(struct httpd *, struct client *, struct stat *); int server_file_method(struct client *); +int parse_range_spec(char *, size_t, struct range *); +struct range *parse_range(char *, size_t, int *); +int buffer_add_range(int, struct evbuffer *, struct range *); int server_file_access(struct httpd *env, struct client *clt, @@ -50,6 +61,7 @@ server_file_access(struct httpd *env, st struct http_descriptor *desc = clt-clt_descreq; struct server_config*srv_conf = clt-clt_srv_conf; struct stat st; + struct kv *r, key; char*newpath; int ret; @@ -123,7 +135,13 @@ server_file_access(struct httpd *env, st goto fail; } - return (server_file_request(env, clt, path, st)); + key.kv_key = Range; + r = kv_find(desc-http_headers, key); + if (r != NULL) + return (server_partial_file_request(env, clt, path, st, + r-kv_value)); + else + return (server_file_request(env, clt, path, st)); fail: switch (errno) { @@ -262,6 +280,138 @@ server_file_request(struct httpd *env, s } int +server_partial_file_request(struct httpd *env, struct client *clt, char *path, +struct stat *st, char *range_str) +{ + struct http_descriptor *resp = clt-clt_descresp; + struct media_type *media, multipart_media; + struct range*range; + struct evbuffer *evb = NULL; + size_t content_length; + int code = 500, fd = -1, i, nranges, ret; + char content_range[64]; + const char *errstr = NULL; + uint32_t boundary; + + if ((range = parse_range(range_str, st-st_size, nranges)) == NULL) { + code = 416; + (void)snprintf(content_range, sizeof(content_range), + bytes */%lld, st-st_size); + errstr = content_range; + goto abort; + } + + /* Now open the file, should be readable or we have another problem */ + if ((fd = open(path, O_RDONLY)) == -1) + goto abort; + + media = media_find(env-sc_mediatypes, path); + if ((evb = evbuffer_new()) == NULL) { + errstr = failed to allocate file buffer; + goto abort; + } + + if (nranges == 1) { + (void)snprintf(content_range, sizeof(content_range), + bytes %lld-%lld/%lld, range-start, range-end, + st-st_size); + if (kv_add(resp-http_headers, Content-Range, + content_range) == NULL) + goto abort; + + content_length = range-end - range-start + 1; + if (buffer_add_range(fd, evb, range) == 0) + goto abort; + + } else { + content_length = 0; + boundary = arc4random(); + /* Generate a multipart payload of byteranges */ + while (nranges--) { + if ((i = evbuffer_add_printf(evb, \r\n--%ud\r\n, + boundary)) == -1) + goto abort; + + content_length += i; + if ((i = evbuffer_add_printf(evb, + Content-Type: %s/%s\r\n, + media
Byte range implementation for httpd(8)
Range requests as defined in RFC7233 is required for resuming interrupted http(s) downloads for example: ftp -C http://foo.bar/install57.iso With this diff, httpd parses Range header in the requests and provide either 206(Partial Content) or 416(Range not Satisfiable) responses with Content-Range header set appropriately. Further, it understands multi range request and generate satisfiable payloads with multipart/byteranges media type. Suggestions/comments to improve the diff are welcome. Note, If-Range isn't implemented yet. Index: server_file.c === RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v retrieving revision 1.51 diff -u -p -r1.51 server_file.c --- server_file.c 12 Feb 2015 10:05:29 - 1.51 +++ server_file.c 17 Apr 2015 02:22:12 - @@ -36,12 +36,23 @@ #define MINIMUM(a, b) (((a) (b)) ? (a) : (b)) #define MAXIMUM(a, b) (((a) (b)) ? (a) : (b)) +#define MAX_RANGES 4 + +struct range { + off_t start; + off_t end; +}; int server_file_access(struct httpd *, struct client *, char *, size_t); int server_file_request(struct httpd *, struct client *, char *, struct stat *); +int server_partial_file_request(struct httpd *, struct client *, char *, + struct stat *, char *); int server_file_index(struct httpd *, struct client *, struct stat *); int server_file_method(struct client *); +int parse_range_spec(char *, size_t, struct range *); +struct range *parse_range(char *, size_t, int *); +int buffer_add_range(int, struct evbuffer *, struct range *); int server_file_access(struct httpd *env, struct client *clt, @@ -50,6 +61,7 @@ server_file_access(struct httpd *env, st struct http_descriptor *desc = clt-clt_descreq; struct server_config*srv_conf = clt-clt_srv_conf; struct stat st; + struct kv *r, key; char*newpath; int ret; @@ -123,7 +135,13 @@ server_file_access(struct httpd *env, st goto fail; } - return (server_file_request(env, clt, path, st)); + key.kv_key = Range; + r = kv_find(desc-http_headers, key); + if (r != NULL) + return (server_partial_file_request(env, clt, path, st, + r-kv_value)); + else + return (server_file_request(env, clt, path, st)); fail: switch (errno) { @@ -262,6 +280,138 @@ server_file_request(struct httpd *env, s } int +server_partial_file_request(struct httpd *env, struct client *clt, char *path, +struct stat *st, char *range_str) +{ + struct http_descriptor *resp = clt-clt_descresp; + struct media_type *media, multipart_media; + struct range*range; + struct evbuffer *evb = NULL; + size_t content_length; + int code = 500, fd = -1, i, nranges, ret; + char content_range[64]; + const char *errstr = NULL; + uint32_t boundary; + + if ((range = parse_range(range_str, st-st_size, nranges)) == NULL) { + code = 416; + (void)snprintf(content_range, sizeof(content_range), + bytes */%lld, st-st_size); + errstr = content_range; + goto abort; + } + + /* Now open the file, should be readable or we have another problem */ + if ((fd = open(path, O_RDONLY)) == -1) + goto abort; + + media = media_find(env-sc_mediatypes, path); + if ((evb = evbuffer_new()) == NULL) { + errstr = failed to allocate file buffer; + goto abort; + } + + if (nranges == 1) { + (void)snprintf(content_range, sizeof(content_range), + bytes %lld-%lld/%lld, range-start, range-end, + st-st_size); + if (kv_add(resp-http_headers, Content-Range, + content_range) == NULL) + goto abort; + + content_length = range-end - range-start + 1; + if (buffer_add_range(fd, evb, range) == 0) + goto abort; + + } else { + content_length = 0; + boundary = arc4random(); + /* Generate a multipart payload of byteranges */ + while (nranges--) { + if ((i = evbuffer_add_printf(evb, \r\n--%ud\r\n, + boundary)) == -1) + goto abort; + + content_length += i; + if ((i = evbuffer_add_printf(evb, + Content-Type: %s/%s\r\n, + media == NULL ? application : media-media_type, + media == NULL ? +
tls_init(3): mention tls_accept_socket function
Hi, tls_accept_socket function missing in tls_init(3) manpage. Index: tls_init.3 === RCS file: /cvs/src/lib/libtls/tls_init.3,v retrieving revision 1.4 diff -u -p -r1.4 tls_init.3 --- tls_init.3 11 Nov 2014 04:17:34 - 1.4 +++ tls_init.3 23 Dec 2014 14:39:06 - @@ -45,6 +45,7 @@ .Nm tls_connect , .Nm tls_connect_fds , .Nm tls_connect_socket , +.Nm tls_accept_socket , .Nm tls_read , .Nm tls_write , .Nd TLS client and server API @@ -105,6 +106,8 @@ .Ft int .Fn tls_connect_socket struct tls *ctx int s const char *hostname .Ft int +.Fn tls_accept_socket struct tls *ctx struct tls **ctx int s +.Ft int .Fn tls_read struct tls *ctx void *buf size_t buflen size_t *outlen .Ft int .Fn tls_write struct tls *ctx const void *buf size_t buflen size_t *outlen @@ -295,6 +298,9 @@ connects a client context to a pair of e .It .Fn tls_connect_socket connects a client context to an already established socket connection. +.It +.Fn tls_accept_socket +accepts a client context on an already established socket connection. .It .Fn tls_read reads
mail(1): new ~i to ignore message headers unconditionally
There isn't a way to reply to a message without pulling in message headers as part of the body. This diff introduces a new tilde escape to ignore all the message headers regardless of ignore, retain commands. Comments? Index: collect.c === RCS file: /cvs/src/usr.bin/mail/collect.c,v retrieving revision 1.33 diff -u -p -r1.33 collect.c --- collect.c 6 Apr 2011 11:36:26 - 1.33 +++ collect.c 7 Jan 2014 13:55:28 - @@ -303,6 +303,7 @@ cont: case 'M': case 'f': case 'F': + case 'i': /* * Interpolate the named messages, if we * are in receiving mail mode. Does the @@ -529,7 +530,12 @@ forward(char *ms, FILE *fp, char *fn, in tabst = NULL; else if ((tabst = value(indentprefix)) == NULL) tabst = \t; - ig = isupper(f) ? NULL : ignore; + if (isupper(f)) + ig = NULL; + else if (f == 'i') + ig = ignoreall; + else + ig = ignore; fputs(Interpolating:, stdout); for (; *msgvec != 0; msgvec++) { struct message *mp = message + *msgvec - 1; Index: mail.1 === RCS file: /cvs/src/usr.bin/mail/mail.1,v retrieving revision 1.61 diff -u -p -r1.61 mail.1 --- mail.1 18 Jul 2013 07:11:00 - 1.61 +++ mail.1 7 Jan 2014 13:55:29 - @@ -768,6 +768,11 @@ Edit the message header fields by typing the user to append text to the end or modify the field by using the current terminal erase and kill characters. .Pp +.It Ic ~i Ns Ar messages +Identical to +.Ic ~m , +except all message headers are excluded. +.Pp .It Ic ~M Ns Ar messages Identical to .Ic ~m ,
list colon modifiers in mail(1) manpage
This diff adds colon modifiers which could be used to specify lists. Index: mail.1 === RCS file: /cvs/src/usr.bin/mail/mail.1,v retrieving revision 1.60 diff -u -p -r1.60 mail.1 --- mail.1 7 Nov 2010 08:05:56 - 1.60 +++ mail.1 12 Jul 2013 10:43:23 - @@ -206,14 +206,28 @@ Thus deletes messages 1 and 2, while .Ic delete 1\-5 deletes messages 1 through 5. -The special name -.Sq * -addresses all messages and -.Sq $ -addresses -the last message; thus the command +.Pp +Some special names could be used to specify a list: +.Bl -tag -width :u +.It * +all messages +.It $ +last message +.It :n +new messages +.It :o +old messages +.It :r +read messages +.It :u +unread messages +.It :d +deleted messages +.El +.Pp +For example, .Ic top -which prints the first few lines of a message could be used in +which prints the first few lines of a message could as well be used as .Ic top * to print the first few lines of all messages. .Ss Replying to or originating mail
pop3 daemon with ssl/tls and STARTTLS, V2
Second iteration... 1. Fixed CRLF issues in RETR and TOP commands that caused message truncation. 2. Properly byte stuff a line beginning with termination character . . 3. Implemented STLS and CAPA. (STARTTLS RFC 2595) Comments? Source: https://poolp.org/~sunil/pop3d.tar.gz uuencoded gzipped tar file... begin 644 pop3d.tar.gz M'XL(`^V]W\:.;(P?/Z%3Z%A9Q)PL(TO7;M)',FR2\ZQBOL23 M,Y.'IPV-W1OH)MW@R\SD^QO773M^#$RSN,;_$TJI))5*I5)5J32.QAO] MU?UFI_7J\+^^TJQUFAL;6[^5Z/16'ORN%_XV=]8V/SO];6U[8V(''KR6-( MAZ=UR/^UF1_ILG$BZ'*9!HPQGYYKW_-_V42B5$P0Z%EXBXBB:EI]`?\ M79[W@3Q_C(%^A!^!Z%?DH]]2+]$()?ETGXC4D$M/$CT67WM;AS5$7`9# M_]SOBW$]?PD$5=,$G*I=X%M@+_#\1#621%2@RB+1M-Y)09Q-!)6M52 M$WIP-@R2^%(A@EY_ZEZ$5A2-VXB878NS%?CB!UWT!^29^*)^BWJ:VN- M6IU`)M6__UQ;44BX`^%B3]$;Q@@`(3J]R8))U_*][N]GC^B--.\[@NCG8[ M'6XCE\F`@@_VH[M[O):5!$Q4+7)#5^/QOESS6PWGD`L`'/6_BKXAV*))I M#QIWD=CZ5V./'A#U;S,!CL^A:#/HKNB=-ZHA@WY-MO#I[;8/3_RXL0G MJ'5Q`94-?4X_.=X][.SNG;3:AXST0A)=@8@FM!F(X/=K?/6D*#IH?Q;A MDO'S7^-CLGW9,W1R_W2[=#T@##/4(%L,@-A$$(K52R]'7G!45!!,7^ M9!H#X4P`08-^783R,91N`:*J+R6@\N+(,LAD[UH?.\X5``A28B!H? M?$'GYRWSQH,MG80P73@I;H3P=LEQ'S`C?XX]9-)%G/4:$9N]\V+]L^B M2A#J!+F;H7`TW`8A!_L%M6%E:+Q;#5:[*!;GM/)[9=D4?5@P%+=`I$3! MH_:'U7F\3%6!1QC`$-NA,TB*#:\I_-6_\=/L1?5]]X'WR(U^GCCGK/[Q; MRZS_6UM/[M?_;_`Y.FZ_E8J\;J]]_)@]U7GT;/2\EOD4\MODTD];+L$9/ MHLG-V$\@;10D216XEV.?6V[_7NSA3,1R877CZ[@QS@*D/TOSLRW;! MGI=,EC]./:HV.`^78=W`9=O*L]]J=SN=@_)^\\4I-GKYO-PYWNO`+U[T5WHB MB,ZF`_JFQV%T#G^1/\$7BQ+\[:_TJ.PCV?=N`DLGHV2)(A_^V.04I)_#%D M/=C?W=_'O,M#_Q+YS/(0,L#?7GPS!LZW/)Q.8%'9/X)LD.O[WP]:+YH_-0]/ M/@GZ#:V6O_:.WQV=M.7#Z4GKX%/YL/UF]_!9N;P2A+WAM.\_/4OZ*X#=\Y71 MA^=?FXGQ_%?X^SIUS)G_3QZOK6?G_Y.U^_G_#3ZK2V6Q)%`TB8/SBXFH]FIB MO='XFVCS!OO2G,O'4AX?_1HD223.*SY]#(2QWY,TX:-0OEU6(''-W4Q MBOK!`+Y1.@'R$;.IBU3Z1318'(%,UN@2.^%-PAH/(W'N(R3M`[)^!U- M)V+@@]R6B`L_]L]NQ'GL`?,`0QFQV70A]W#Y,*#S*%+[RSZ-)'2#W=%9P M@IY/3:!ZQZ:QZM5X['LQH;([J!DXKLFLGKYNBTWYY\G;WN`ERL@!^5-K MO[DO*KL=*Z(W-]RH3B_M8[+ZP[(.6(W8,#`:5`!#YI-3L(ZVT+).SC MYJO=8RC2AE(`S\`^W#LXW6\=OJ*K3='!RVHQ0`0[9(XTWS.\UI.R^:!VT M3MY1]2];)X?-3F%8(C#MB.(SJO$8[5LA=-=#:?0'RYOV,8+:/7PG.D?- MO=;N01W:?=S.ZD#/4+BNRU#SLH]T(#=@_$_NZ;W5?8D,J*A^I8Z]W3SIM MJ/8NMY/3C!;KP\;K\1!^T.MAPW15#'[LDNE@80I,[=2C7A`88[MW#ZE) MO%``E`U[!ZP'8?-5PM5\W#O2:6;5.!D_8Q9#SMR`)UL7OZFE[=,3B:@V M@04PATT2MA'?$!;J!7-8T`$\%P$_-(=#1S]U7+Y+Y(5BZ?)3;(*RY`W6KEX MGDH`7SJ9Y.3J/?!GV33IT$B5:J'\=AE,HXZ0?9I%PEDZ+89%UTX`_05:W MBHID[!5ODROIR=]SU^OTJP)CV)FJ_O%3;7+`I!U[D]Y%%9;KND@NHAB^ M*$-.3BEUIT'6869-(#=E+\OL01AD,@;^)6E[1=7`ILKU[;2`]5Y=Z,$7/ MO-Z'6FXMT$23DUTBH:^WX?M;:;'M?+O91(=N%$/H!G+SX%1#K0$AWB1(F MR#9W',]$PWH#*=B^R`!OU1W@#'D)KHJ@N@`YU$_UBIL(+_B'KH:DC032 MFS_!3G1W'_)3$L@KJL$.]7R%2@55(^R*;14TW#0HP,`Y/#P[@W:=R?I M1@N%,.#+N0,V!;1-UK:ZP(!!I3/^OP//9APCS$QU8M#/'60+#CX/_9#' M)9R48L2#0JANBSU.7+.LCZM`\`Q8@4,D#T0U%M\]$\MKM;*2%PD!C!HAK4` MU9AQ8),L[3!S4,#M3-/(VDXYS\#$=:=(H@\.'U_J`'P9H,RI$'!RA6^ MY!;:5)M,V?.JQIIITK35`\:^SN'F,LA2,QIM6%^)?_/'*S^!Y5_ M]PZ:6)=JTLBD^4?`;;1BV1?(A`OP^^`B%6@]E5H_R!=7G#V/?Z-P+2 MD%=3]:I5SVS:Q_IX5+/3B7_L%'[Z\\QV1L7DOD2^,AL`#/DXOI:#SV*CL M$2SA$)O^/V.\Q8:J_A+[PWY.+F*=%?3$NW_SNI%02.;C2Y`!U/5#C7A._ MXSRUJH)BB.2Q5KJ=5P*J4287LAXY8M^%#ZB`OOTA=^$W/+ZW@+Y! M#%)%/HE=LD(MO:RY!EHG$6)S]]5NZU!M1FGG68FM,:@$XE^!IWE M[#)W`WU5=#7)G6602MB(FC\7\-KZ+[B7Q*IE28*!5B:H'V2+%=L'BS;`Q( M\9)D.O)EJ6N;UA$ME%KFS3$4@4H`/B`1Q-5:$`Y?)X@B3=$*M8X?, MQ]Q4@;XY,S?FOA1XX`FJMA6S_OMPR:CQ`$D/$I1294BM%6$%Y$21\$N%Q MNVU45]V0)-]S$.?#1L/N31CI([[@R0::3STM/8[Z^(%Q'L'7H[)P MX'ZU=COP:X@]LZ/D,@!2M60F(;`B2,59UZ2O43F!T)C@*'HRX'Y3-2ME MA4I-\Y(C4S=@CL/OY=70/JPRBCBFD-;C*%\3%Y=H,ZZFEY-*6Y4^\6!6O MB`_P.34!YS0#OW-:81,WOCP#W*#`X@HS#BC\4DW8DML%Z=W5:I*DEU[,$# MD;.6-V=V05-D;H#5,V5;A8M4:2_J^V:9=_N,[RR6_F?OY#_OX^A_+KY. M'7/T/QMKC2Y^I_U_W/-_CZW_N]3_W^I^L_F0]OV!Z';E`O.ZVRW_!5( MD%*=1%N=@P*SJY-!OLH:5F6K*`'S/JJ%:JPA_8-O3C%=BDBF5^]QK$S9Q MM]/ZGV:M7':7I=\S`KZ0,CVN:J52=4GN06KY6AM5FAI:@B]=DGJ,7@C6#+; M(]R%EX1IJVJ;J/L0H6:6-@#=UQ$24%BE(CG8K+?6DMG4JBFD]DTQ25FDC MDTZP-UW%6)YV2G:(T5A72J5LOTG=D:+*BQ2@TZCE*%J+]V6H22\OB_,1J MCK++I'2UN7J,C)YK03J3Y^XK!@+V_8P!GS9R]C]Y_/_$CYC\VF7ZF. MV?+?VI.-C8V,_/X\?A_OLG]6ETO=M$.Q=/:_+^'2!Y.;/GEBX=KZO5AX M+Q;^;Q8+;8,^;[L?UO(R21KH'=D$!RC12A:DP6G;Y(,5Z$Q;EGU`OUA M\`6M_8YMD18--UJR:K]XO1E]\WNSZ6MQX\WMMST?W3?M`Y+FXV_;1FY-OK( M:FKZ[L)LBWI:[D#H*,FP:EJ**,THMN/_:L#@OV[`HIR/28@4EGI2S^, MOM2]HS\$K^,5N#7T94JJ8TX9!1Z\7HM^FZRH*E=!Y^0/C.Z^=8TD;GY;7 M=!50^_)S5M^/)*@OV2.44PQ*R)KP:X=3N'VR:E6B86O#(F-82N/)L3G( MT?JHFBA;BTA'9]ZWC'JR^I'U%!.G#MCS6IRI./\.8C*OO)SL*PDE(P= M@2HV*-/P/$JP!CBTNERNE#2)H^A/YB@Y;6PV:BQ$R6XA4:?@4K$^S:X!N M43483).G)%/%HV42LI564^#U*O'\*Z]KM.7R9DN#I5#ZV+'1IU3MDEI3 M`%;%'24U:,,%L,Q]*/2AEZ+-D8P`FY$)U,._G8;=WX6EI8FBBQ!P(2FO M@+@572X+3;-/$58F,S8K]IG^)7G539E'0AMW)XO,BTTRB4SLR8YX)[)ON/ M,R?%,IK7,'FKES1L*6A).OYR\*IJK@2)!$77DMRQ)]F(*@'!L0)11LX= MV/;/A8+)CUP@SO2+QO/H0Q+%,V:CC-9P.:*L],D^4D97YD9E28;8GY_YD M$M-IB5$,+(Q2[%R+FE?90Y@,P64(@+20(I@T+0_03*0T5-6XO%+]#H;4: M4,M%`.A:$T]QZH?P].A13;(-R/Q+\!XI]OX4-C'3V,)OXVR:O99C7K\? MX[$8\I=-'\?L$*:Y1V/_@U\.,5@68U(/UE](T/)B0_]Z+PT@\#/^SY6MKN M7%?ED1(9'@S!C)JC(SJCA\6/1C_PD?*ALC62\A;;T(Z@*JCY1D)_!'PX
Re: tinyscheme + mg
On Thu, Jun 28, 2012 at 10:05:49PM +0500, Mark Lumsden wrote: I'd be a lot happier voicing an opinion in support of something like this if I also saw diffs and interest in *using* them to extend functionality later or replace some things easier to do with scheme to make the code simpler - something kjell was alluding to. I think we can work towards that, but there's a bit of chicken and egg problem here. I'm not inclined to do a lot of work if the answer in two months is going to be oh, sorry, perl would have been cooler. The diff will only get larger from here. A promise of this is bigger and bloated now but will be really cool in the future isn't so good if the people putting it in see getting scheme integration in as the goal - otherwise, congrats, you've Integration is one of the goals. I can't predict what extensions you may want to write. I mean, mg already reads a .mg file. If we knew what people were going to put in their .mg files, we could just hard code it in the program and cut out the startup file bloat. That said, some concrete examples would help, both to make sure we're building something useful and to demonstrate that it is useful. Why do people still use emacs and not mg? For text editing not usenet browsing or whatever. +1 to somebody providing concrete examples. Hooks. Inspite of reading jmc@'s request on src@ to check for trailing whitespace in manpages, I happened to send one diff for review which had trailing whitespace. This could be avoided with a before-save-hook that can truncate trailing spaces. Also what if one wants to run something else while C files are being loaded into mg apart from the auto-execute c-mode hack. Here is a diff that adds hooks support I sent sometime ago, but not everyone would like to write their hooks in C. http://marc.info/?l=openbsd-techm=132993761420531w=2 PS: mandoc -Tlint complained but I missed it.
Re: cscope support in mg
Here is an updated diff with following changes... Manpage update. Remove conditional compilation of cscope functionality. Fixed a memory leak in csexists function. Treat current word at cursor as default input for cscope commands. Comments? Index: Makefile === RCS file: /cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.25 diff -u -p -r1.25 Makefile --- Makefile28 Nov 2011 04:41:39 - 1.25 +++ Makefile14 May 2012 17:43:32 - @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c tags.c theo.c +SRCS+= cmode.c cscope.c dired.c grep.c tags.c theo.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: README === RCS file: /cvs/src/usr.bin/mg/README,v retrieving revision 1.8 diff -u -p -r1.8 README --- README 1 Aug 2011 12:15:23 - 1.8 +++ README 14 May 2012 17:40:21 - @@ -63,6 +63,12 @@ bytes. +While navigating source code using Mg's cscope commands, the cursor +is always at the match location rather than in *cscope* buffer. Mg uses +the same keybindings of GNU Emacs's xcscope package for it's cscope commands. +As Mg's keybindings are case-insensitive some of the commands don't have a +default keybinding. + New implementation oddities: insert and define-key are new commands corresponding to the mocklisp Index: cscope.c === RCS file: cscope.c diff -N cscope.c --- /dev/null 1 Jan 1970 00:00:00 - +++ cscope.c30 May 2012 16:41:25 - @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2012 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/types.h +#include sys/stat.h +#include sys/queue.h + +#include ctype.h +#include fcntl.h +#include fnmatch.h +#include stdio.h +#include stdlib.h +#include string.h + +#include def.h + +#define CSSYMBOL 0 +#define CSDEFINITION 1 +#define CSCALLEDFUNCS 2 +#define CSCALLERFUNCS 3 +#define CSTEXT4 +#define CSEGREP 6 +#define CSFINDFILE7 +#define CSINCLUDES8 + +struct cstokens { + const char *fname; + const char *function; + const char *lineno; + const char *pattern; +}; + +struct csmatch { + TAILQ_ENTRY(csmatch) entry; + int lineno; +}; + +struct csrecord { + TAILQ_ENTRY(csrecord) entry; + char *filename; + TAILQ_HEAD(matches, csmatch) matches; +}; + +static TAILQ_HEAD(csrecords, csrecord) csrecords = TAILQ_HEAD_INITIALIZER(csrecords); +static struct csrecord *addentryr; +static struct csrecord *currecord; +static struct csmatch *curmatch; +static const char *addentryfn; +static const char *csprompt[] = { + Find this symbol: , + Find this global definition: , + Find functions called by this function: , + Find functions calling this function: , + Find this text string: , + Change this text string: , + Find this egrep pattern: , + Find this file: , + Find files #including this file: +}; + +static int addentry(struct buffer *, char *); +static void csflush(void); +static int do_cscope(int); +static int csexists(const char *); +static int getattr(char *, struct cstokens *); +static int jumptomatch(void); +static void prettyprint(struct buffer *, struct cstokens *); +static const char *ltrim(const char *); + +/* + * Find this symbol. Bound to C-c s s + */ +/* ARGSUSED */ +int +cssymbol(int f, int n) +{ + return (do_cscope(CSSYMBOL)); +} + +/* + * Find this global definition. Bound to C-c s d + */ +/* ARGSUSED */int +csdefinition(int f, int n) +{ + return (do_cscope(CSDEFINITION)); +} + +/* + * Find functions called by this function. Bound to C-c s l + */ +/* ARGSUSED */ +int +csfuncalled(int f, int n) +{ + return (do_cscope(CSCALLEDFUNCS)); +} + +/* + * Find functions calling this function. Bound to C-c s c + */ +/* ARGSUSED */ +int +cscallerfuncs(int f, int n) +{ + return (do_cscope(CSCALLERFUNCS)); +} + +/* + * Find this text. Bound to C-c s t + */ +/* ARGSUSED */ +int +csfindtext(int f, int n) +{ + return (do_cscope(CSTEXT
Re: Pipe text from mg to external command
A refined version of the diff with 2 less bugs and shorter by ~40 or so lines. Changes from previous version... Reuse region_get_data() to extract C string from selected region instead of custom line by line iteration, thereby reducing number of send(2) syscalls. Fix a bug which causes gratuitous text from previous invocation to appear if previous command input's last line doesn't have a '\n'. Fix a crash issue when a region from Shell Command Ouput buffer is pipe'd to external command. Index: README === RCS file: /cvs/src/usr.bin/mg/README,v retrieving revision 1.8 diff -u -p -r1.8 README --- README 1 Aug 2011 12:15:23 - 1.8 +++ README 5 Apr 2012 19:02:18 - @@ -61,7 +61,9 @@ recognized as special cases. On systems with 16 bit integers, the kill buffer cannot exceed 32767 bytes. - +Unlike GNU Emacs, Mg's minibuffer isn't multi-line aware and hence +some commands like shell-command-on-region always pop up a buffer to +display output irrespective of output's size. New implementation oddities: Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.118 diff -u -p -r1.118 def.h --- def.h 10 Dec 2011 14:09:48 - 1.118 +++ def.h 16 Mar 2012 04:59:14 - @@ -567,6 +567,8 @@ int prefixregion(int, int); int setprefix(int, int); int region_get_data(struct region *, char *, int); voidregion_put_data(const char *, int); +int markbuffer(int, int); +int piperegion(int, int); /* search.c X */ int forwsearch(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.36 diff -u -p -r1.36 funmap.c --- funmap.c14 Mar 2012 13:56:35 - 1.36 +++ funmap.c16 Mar 2012 04:59:14 - @@ -113,6 +113,7 @@ static struct funmap functnames[] = { {localbind, local-set-key,}, {localunbind, local-unset-key,}, {makebkfile, make-backup-files,}, + {markbuffer, mark-whole-buffer,}, {do_meta, meta-key-mode,},/* better name, anyone? */ {negative_argument, negative-argument,}, {newline, newline,}, @@ -166,6 +167,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB {space_to_tabstop, space-to-tabstop,}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.47 diff -u -p -r1.47 keymap.c --- keymap.c14 Mar 2012 13:56:35 - 1.47 +++ keymap.c16 Mar 2012 04:59:14 - @@ -135,7 +135,7 @@ static PF cXcar[] = { #endif /* !NO_MACRO */ setfillcol, /* f */ gotoline, /* g */ - rescan, /* h */ + markbuffer, /* h */ fileinsert, /* i */ rescan, /* j */ killbuffer_cmd, /* k */ @@ -257,7 +257,7 @@ static PF metal[] = { rescan, /* y */ rescan, /* z */ gotobop,/* { */ - rescan, /* | */ + piperegion, /* | */ gotoeop /* } */ }; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.58 diff -u -p -r1.58 mg.1 --- mg.19 Feb 2012 09:00:14 - 1.58 +++ mg.116 Mar 2012 04:59:14 - @@ -196,6 +196,8 @@ call-last-kbd-macro set-fill-column .It C-x g goto-line +.It C-x h +mark-whole-buffer .It C-x i insert-file .It C-x k @@ -260,6 +262,8 @@ copy-region-as-kill execute-extended-command .It M-{ backward-paragraph +.It M-| +shell-command-on-region .It M-} forward-paragraph .It M-~ @@ -572,6 +576,9 @@ Bind a key mapping in the local (topmost Unbind a key mapping in the local (topmost) mode. .It make-backup-files Toggle generation of backup files. +.It mark-whole-buffer +Marks whole buffer as a region by putting dot at the beginning and mark +at the end of buffer. .It meta-key-mode When disabled, the meta key can be used to insert extended-ascii (8-bit) characters. @@ -734,6 +741,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command-on-region +Provide the text in region to the shell command as input. .It shrink-window Shrink current window by one line. The window immediately below is expanded to pick up the slack. Index: region.c
Re: Pipe text from mg to external command
This version implements some off-list review comments... 1. Discard explicit checking whether command exists and it's permissions since shell already does and reports error. 2. Remove unnecessary bzero call. 3. Document minor deviation from emacs behaviour in README. Index: README === RCS file: /cvs/src/usr.bin/mg/README,v retrieving revision 1.8 diff -u -p -r1.8 README --- README 1 Aug 2011 12:15:23 - 1.8 +++ README 20 Mar 2012 17:54:12 - @@ -61,7 +61,9 @@ recognized as special cases. On systems with 16 bit integers, the kill buffer cannot exceed 32767 bytes. - +Unlike GNU Emacs, Mg's minibuffer isn't multi-line aware and hence +some commands like shell-command-on-region always pop up a buffer to +display output irrespective of output's size. New implementation oddities: Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.118 diff -u -p -r1.118 def.h --- def.h 10 Dec 2011 14:09:48 - 1.118 +++ def.h 16 Mar 2012 04:59:14 - @@ -567,6 +567,8 @@ int prefixregion(int, int); int setprefix(int, int); int region_get_data(struct region *, char *, int); voidregion_put_data(const char *, int); +int markbuffer(int, int); +int piperegion(int, int); /* search.c X */ int forwsearch(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.36 diff -u -p -r1.36 funmap.c --- funmap.c14 Mar 2012 13:56:35 - 1.36 +++ funmap.c16 Mar 2012 04:59:14 - @@ -113,6 +113,7 @@ static struct funmap functnames[] = { {localbind, local-set-key,}, {localunbind, local-unset-key,}, {makebkfile, make-backup-files,}, + {markbuffer, mark-whole-buffer,}, {do_meta, meta-key-mode,},/* better name, anyone? */ {negative_argument, negative-argument,}, {newline, newline,}, @@ -166,6 +167,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB {space_to_tabstop, space-to-tabstop,}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.47 diff -u -p -r1.47 keymap.c --- keymap.c14 Mar 2012 13:56:35 - 1.47 +++ keymap.c16 Mar 2012 04:59:14 - @@ -135,7 +135,7 @@ static PF cXcar[] = { #endif /* !NO_MACRO */ setfillcol, /* f */ gotoline, /* g */ - rescan, /* h */ + markbuffer, /* h */ fileinsert, /* i */ rescan, /* j */ killbuffer_cmd, /* k */ @@ -257,7 +257,7 @@ static PF metal[] = { rescan, /* y */ rescan, /* z */ gotobop,/* { */ - rescan, /* | */ + piperegion, /* | */ gotoeop /* } */ }; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.58 diff -u -p -r1.58 mg.1 --- mg.19 Feb 2012 09:00:14 - 1.58 +++ mg.116 Mar 2012 04:59:14 - @@ -196,6 +196,8 @@ call-last-kbd-macro set-fill-column .It C-x g goto-line +.It C-x h +mark-whole-buffer .It C-x i insert-file .It C-x k @@ -260,6 +262,8 @@ copy-region-as-kill execute-extended-command .It M-{ backward-paragraph +.It M-| +shell-command-on-region .It M-} forward-paragraph .It M-~ @@ -572,6 +576,9 @@ Bind a key mapping in the local (topmost Unbind a key mapping in the local (topmost) mode. .It make-backup-files Toggle generation of backup files. +.It mark-whole-buffer +Marks whole buffer as a region by putting dot at the beginning and mark +at the end of buffer. .It meta-key-mode When disabled, the meta key can be used to insert extended-ascii (8-bit) characters. @@ -734,6 +741,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command-on-region +Provide the text in region to the shell command as input. .It shrink-window Shrink current window by one line. The window immediately below is expanded to pick up the slack. Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.29 diff -u -p -r1.29 region.c --- region.c5 Jun 2009 18:02:06 - 1.29 +++ region.c21 Mar 2012
Re: Pipe text from mg to external command
Third attempt, and these are the changes done since the first version of this diff. 1. Check for existence of the command to be executed and also the permissions. 2. Replace popen(3) which messed stdout with socketpair(2), fork(2) and execl(2). 3. IO multiplexing using poll(2) to prevent deadlock while transferring large text to and from external command. 4. Fixed a memory leak while using strdup(3). 5. style(9) consistencies. In emacs, if the output from the command is less than 12 lines, it shows the output in minibuffer otherwise emacs pops up a *Shell Command Output* buffer and displays in it. Since mg's minibuffer isn't multi-line aware, this diff pops up *Shell Command Output* and displays output in that buffer irrespective of output's size. Comments? Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.118 diff -u -p -r1.118 def.h --- def.h 10 Dec 2011 14:09:48 - 1.118 +++ def.h 16 Mar 2012 04:59:14 - @@ -567,6 +567,8 @@ int prefixregion(int, int); int setprefix(int, int); int region_get_data(struct region *, char *, int); voidregion_put_data(const char *, int); +int markbuffer(int, int); +int piperegion(int, int); /* search.c X */ int forwsearch(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.36 diff -u -p -r1.36 funmap.c --- funmap.c14 Mar 2012 13:56:35 - 1.36 +++ funmap.c16 Mar 2012 04:59:14 - @@ -113,6 +113,7 @@ static struct funmap functnames[] = { {localbind, local-set-key,}, {localunbind, local-unset-key,}, {makebkfile, make-backup-files,}, + {markbuffer, mark-whole-buffer,}, {do_meta, meta-key-mode,},/* better name, anyone? */ {negative_argument, negative-argument,}, {newline, newline,}, @@ -166,6 +167,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB {space_to_tabstop, space-to-tabstop,}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.47 diff -u -p -r1.47 keymap.c --- keymap.c14 Mar 2012 13:56:35 - 1.47 +++ keymap.c16 Mar 2012 04:59:14 - @@ -135,7 +135,7 @@ static PF cXcar[] = { #endif /* !NO_MACRO */ setfillcol, /* f */ gotoline, /* g */ - rescan, /* h */ + markbuffer, /* h */ fileinsert, /* i */ rescan, /* j */ killbuffer_cmd, /* k */ @@ -257,7 +257,7 @@ static PF metal[] = { rescan, /* y */ rescan, /* z */ gotobop,/* { */ - rescan, /* | */ + piperegion, /* | */ gotoeop /* } */ }; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.58 diff -u -p -r1.58 mg.1 --- mg.19 Feb 2012 09:00:14 - 1.58 +++ mg.116 Mar 2012 04:59:14 - @@ -196,6 +196,8 @@ call-last-kbd-macro set-fill-column .It C-x g goto-line +.It C-x h +mark-whole-buffer .It C-x i insert-file .It C-x k @@ -260,6 +262,8 @@ copy-region-as-kill execute-extended-command .It M-{ backward-paragraph +.It M-| +shell-command-on-region .It M-} forward-paragraph .It M-~ @@ -572,6 +576,9 @@ Bind a key mapping in the local (topmost Unbind a key mapping in the local (topmost) mode. .It make-backup-files Toggle generation of backup files. +.It mark-whole-buffer +Marks whole buffer as a region by putting dot at the beginning and mark +at the end of buffer. .It meta-key-mode When disabled, the meta key can be used to insert extended-ascii (8-bit) characters. @@ -734,6 +741,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command-on-region +Provide the text in region to the shell command as input. .It shrink-window Shrink current window by one line. The window immediately below is expanded to pick up the slack. Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving revision 1.29 diff -u -p -r1.29 region.c --- region.c5 Jun 2009 18:02:06 - 1.29 +++ region.c18 Mar 2012 17:39:32 - @@ -9,9 +9,26 @@ * internal use. */ +#include sys/types.h +#include sys/socket.h
Re: Pipe text from mg to external command
This version properly captures data from external command and puts it into *Shell Command Output* buffer. These are the new commands added to mg with this diff... C-x h mark-whole-buffer M-| shell-command-on-region Comments? Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.77 diff -u -p -r1.77 buffer.c --- buffer.c23 Jan 2011 00:45:03 - 1.77 +++ buffer.c10 Mar 2012 12:30:19 - @@ -792,10 +792,8 @@ notmodified(int f, int n) return (TRUE); } -#ifndef NO_HELP /* - * Popbuf and set all windows to top of buffer. Currently only used by - * help functions. + * Popbuf and set all windows to top of buffer. */ int popbuftop(struct buffer *bp, int flags) @@ -814,7 +812,6 @@ popbuftop(struct buffer *bp, int flags) } return (popbuf(bp, flags) != NULL); } -#endif /* * Return the working directory for the current buffer, terminated Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.118 diff -u -p -r1.118 def.h --- def.h 10 Dec 2011 14:09:48 - 1.118 +++ def.h 10 Mar 2012 12:30:19 - @@ -567,6 +567,8 @@ int prefixregion(int, int); int setprefix(int, int); int region_get_data(struct region *, char *, int); voidregion_put_data(const char *, int); +int markbuffer(int, int); +int piperegion(int, int); /* search.c X */ int forwsearch(int, int); Index: funmap.c === RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.35 diff -u -p -r1.35 funmap.c --- funmap.c28 Nov 2011 04:41:39 - 1.35 +++ funmap.c10 Mar 2012 12:30:19 - @@ -119,6 +119,7 @@ static struct funmap functnames[] = { {localbind, local-set-key,}, {localunbind, local-unset-key,}, {makebkfile, make-backup-files,}, + {markbuffer, mark-whole-buffer,}, {do_meta, meta-key-mode,},/* better name, anyone? */ {negative_argument, negative-argument,}, {newline, newline,}, @@ -172,6 +173,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {piperegion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB {space_to_tabstop, space-to-tabstop,}, Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.46 diff -u -p -r1.46 keymap.c --- keymap.c28 Nov 2011 04:41:39 - 1.46 +++ keymap.c10 Mar 2012 12:30:19 - @@ -137,7 +137,7 @@ static PF cXcar[] = { #endif /* !NO_MACRO */ setfillcol, /* f */ gotoline, /* g */ - rescan, /* h */ + markbuffer, /* h */ fileinsert, /* i */ rescan, /* j */ killbuffer_cmd, /* k */ @@ -259,7 +259,7 @@ static PF metal[] = { rescan, /* y */ rescan, /* z */ gotobop,/* { */ - rescan, /* | */ + piperegion, /* | */ gotoeop /* } */ }; Index: mg.1 === RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.58 diff -u -p -r1.58 mg.1 --- mg.19 Feb 2012 09:00:14 - 1.58 +++ mg.110 Mar 2012 12:30:22 - @@ -196,6 +196,8 @@ call-last-kbd-macro set-fill-column .It C-x g goto-line +.It C-x h +mark-whole-buffer .It C-x i insert-file .It C-x k @@ -260,6 +262,8 @@ copy-region-as-kill execute-extended-command .It M-{ backward-paragraph +.It M-| +shell-command-on-region .It M-} forward-paragraph .It M-~ @@ -572,6 +576,9 @@ Bind a key mapping in the local (topmost Unbind a key mapping in the local (topmost) mode. .It make-backup-files Toggle generation of backup files. +.It mark-whole-buffer +Marks whole buffer as a region by putting dot at the beginning and mark +at the end of buffer. .It meta-key-mode When disabled, the meta key can be used to insert extended-ascii (8-bit) characters. @@ -734,6 +741,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command-on-region +Provide the text in region to the shell command as input. .It shrink-window Shrink current window by one line. The window immediately below is expanded to pick up the slack. Index: region.c === RCS file: /cvs/src/usr.bin/mg/region.c,v retrieving
cscope support in mg
On Fri, Sep 02, 2011 at 02:23:28PM -0300, Christiano F. Haesbaert wrote: On 2 September 2011 14:17, Matthew Dempsky matt...@dempsky.org wrote: On Fri, Sep 2, 2011 at 8:55 AM, Sunil Nimmagadda su...@sunilnimmagadda.com wrote: This diff adds tags support to Mg. I am NOT an emacs user so if this combination is a bit odd then please excuse. It parses the tags file generated by ctags(1) and maintains a tree. M-. on first character of a word jumps to it's definition and M-* jumps back to previous location. I'd love to have ctags support in mg. cscope would be cool too, if not too much bloat. This diff adds some cscope support in mg. Keybindings are same as xcscope that comes with emacs. Find this symbol C-c s s Find this global definition C-c s d Find functions called by this function C-c s l Find functions calling this function C-c s c Find this text C-c s t Find this egrep pattern C-c s e Find this file C-c s f Find files #including this file C-c s i Find next symbol C-c s n Find prev symbol C-c s p Comments? Index: Makefile === RCS file: /home/sunil/cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.25 diff -u -p -r1.25 Makefile --- Makefile28 Nov 2011 04:41:39 - 1.25 +++ Makefile29 Feb 2012 18:06:23 - @@ -2,6 +2,9 @@ PROG= mg +#Uncomment to build cscope support. Cscope package is required. +CSCOPE= yes + LDADD+=-lcurses -lutil DPADD+=${LIBCURSES} ${LIBUTIL} @@ -25,6 +28,11 @@ SRCS=autoexec.c basic.c buffer.c cinfo. # More or less standalone extensions. # SRCS+= cmode.c dired.c grep.c tags.c theo.c + +.ifdef CSCOPE +CFLAGS+= -DCSCOPE +SRCS+= cscope.c +.endif afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: buffer.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.77 diff -u -p -r1.77 buffer.c --- buffer.c23 Jan 2011 00:45:03 - 1.77 +++ buffer.c29 Feb 2012 16:51:02 - @@ -792,10 +792,8 @@ notmodified(int f, int n) return (TRUE); } -#ifndef NO_HELP /* - * Popbuf and set all windows to top of buffer. Currently only used by - * help functions. + * Popbuf and set all windows to top of buffer. */ int popbuftop(struct buffer *bp, int flags) @@ -814,7 +812,6 @@ popbuftop(struct buffer *bp, int flags) } return (popbuf(bp, flags) != NULL); } -#endif /* * Return the working directory for the current buffer, terminated Index: cscope.c === RCS file: cscope.c diff -N cscope.c --- /dev/null 1 Jan 1970 00:00:00 - +++ cscope.c29 Feb 2012 17:49:50 - @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2012 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h + +#include stdio.h +#include stdlib.h +#include string.h + +#include def.h + +struct csmatch { + TAILQ_ENTRY(csmatch) entry; + int lineno; +}; + +struct csrecord { + TAILQ_ENTRY(csrecord) entry; + char *filename; + TAILQ_HEAD(matches, csmatch) matches; +}; + +static TAILQ_HEAD(csrecords, csrecord) csrecords = TAILQ_HEAD_INITIALIZER(csrecords); +static struct csrecord *addentryr; +static struct csrecord *currecord; +static struct csmatch *curmatch; +static const char *addentryfn; +static const char *csprompt[] = { + Find this symbol: , + Find this global definition: , + Find functions called by this function: , + Find functions calling this function: , + Find this text string: , + Change this text string: , + Find this egrep pattern: , + Find this file: , + Find files #including this file: +}; + +static int addentry(const char *); +static void csflush(); +static int do_cscope(int); +static int getattr(const char *, char **, int *); +static int jumptomatch(); + +/* + * Find this symbol. Bound to C-c s s + */ +/* ARGSUSED */ +int +cssymbol(int f, int n) +{ + return (do_cscope(0)); +} + +/* + * Find this global definition. Bound to C-c s d + */ +/* ARGSUSED */int +csdefinition(int f, int n) +{ + return (do_cscope(1
Hooks in mg
Hello, This diff generalize the hooks execution and allows to define new hook execution points. For example if your .mg is now... auto-execute *.c c-mode then with this diff you can change it to... add-hook find-file-hook c-mode add-hook before-save-hook deltrailspace find-file-hook type hooks get executed every time a file is read in and before-save-hook type hooks get executed when a buffer is about to be saved. deltrailspace is a hook that removes trailing whitespace before saving a buffer whose filename matches *.[ch1-9] comments? Index: Makefile === RCS file: /home/sunil/cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.25 diff -u -p -r1.25 Makefile --- Makefile28 Nov 2011 04:41:39 - 1.25 +++ Makefile22 Feb 2012 18:06:59 - @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c tags.c theo.c +SRCS+= cmode.c dired.c hookexec.c hooks.c grep.c tags.c theo.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: def.h === RCS file: /home/sunil/cvs/src/usr.bin/mg/def.h,v retrieving revision 1.118 diff -u -p -r1.118 def.h --- def.h 10 Dec 2011 14:09:48 - 1.118 +++ def.h 22 Feb 2012 18:09:04 - @@ -654,6 +654,19 @@ int next_error(int, int); int globalwdtoggle(int, int); int compile(int, int); +/* hooks.c */ +void cmode_hook(void); +void deltspace_hook(void); + +/* hookexec.c */ +enum hooktype { + HOOKTYPE_UNDEF, + HOOKTYPE_FIND_FILE, + HOOKTYPE_BEFORE_SAVE +}; +intaddhook(int, int); +void exechooks(enum hooktype); + /* * Externals. */ Index: file.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/file.c,v retrieving revision 1.76 diff -u -p -r1.76 file.c --- file.c 31 Aug 2011 08:58:29 - 1.76 +++ file.c 22 Feb 2012 18:11:38 - @@ -238,6 +238,8 @@ readin(char *fname) free(ael); } + exechooks(HOOKTYPE_FIND_FILE); + /* no change */ curbp-b_flag = ~BFCHG; @@ -572,6 +574,8 @@ buffsave(struct buffer *bp) return (s); } + exechooks(HOOKTYPE_BEFORE_SAVE); + if (makebackup (bp-b_flag BFBAK)) { s = fbackupfile(bp-b_fname); /* hard error */ Index: funmap.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.35 diff -u -p -r1.35 funmap.c --- funmap.c28 Nov 2011 04:41:39 - 1.35 +++ funmap.c22 Feb 2012 18:13:32 - @@ -21,6 +21,7 @@ static struct funmap *funs; static struct funmap functnames[] = { #ifndefNO_HELP + {addhook, add-hook,}, {apropos_command, apropos,}, #endif /* !NO_HELP */ {auto_execute, auto-execute, }, Index: hookexec.c === RCS file: hookexec.c diff -N hookexec.c --- /dev/null 1 Jan 1970 00:00:00 - +++ hookexec.c 22 Feb 2012 19:00:40 - @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h +#include sys/tree.h + +#include def.h + +struct hook; +typedef void (*HF)(void); + +static int hcmp(struct hook *, struct hook *); +static enum hooktype hlookup(char *); +static int addhook_helper(enum hooktype, HF); +static HF hfunction(const char *); + +struct hfname +{ + HF fp; + const char *name; +}; + +static struct hfname hfuncnames [] = { + {cmode_hook, c-mode}, + {deltspace_hook, deltrailspace}, + {NULL, NULL} +}; + +struct hookfunc { + SLIST_ENTRY(hookfunc) entry; + HFfp; +}; + +struct hook { + RB_ENTRY(hook) entry; + SLIST_HEAD(, hookfunc) hfuncs; + enum hooktype t; + +}; + +/* key is enum hooktype and value is a list of HF. */ +static RB_HEAD(hookmap, hook) hmap = RB_INITIALIZER(hmap); +RB_GENERATE
Pipe text from mg to external command
This diff allows a user pipe text from current region in mg to external command. Also adds a command to mark whole buffer. Comments? Index: def.h === RCS file: /home/sunil/cvs/src/usr.bin/mg/def.h,v retrieving revision 1.118 diff -u -p -r1.118 def.h --- def.h 10 Dec 2011 14:09:48 - 1.118 +++ def.h 25 Dec 2011 19:18:58 - @@ -567,6 +567,8 @@ int prefixregion(int, int); int setprefix(int, int); int region_get_data(struct region *, char *, int); voidregion_put_data(const char *, int); +int markbuffer(int, int); +int cmdregion(int, int); /* search.c X */ int forwsearch(int, int); Index: funmap.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.35 diff -u -p -r1.35 funmap.c --- funmap.c28 Nov 2011 04:41:39 - 1.35 +++ funmap.c25 Dec 2011 19:24:00 - @@ -119,6 +119,7 @@ static struct funmap functnames[] = { {localbind, local-set-key,}, {localunbind, local-unset-key,}, {makebkfile, make-backup-files,}, + {markbuffer, mark-whole-buffer,}, {do_meta, meta-key-mode,},/* better name, anyone? */ {negative_argument, negative-argument,}, {newline, newline,}, @@ -172,6 +173,7 @@ static struct funmap functnames[] = { {setfillcol, set-fill-column,}, {setmark, set-mark-command,}, {setprefix, set-prefix-string,}, + {cmdregion, shell-command-on-region,}, {shrinkwind, shrink-window,}, #ifdef NOTAB {space_to_tabstop, space-to-tabstop,}, Index: keymap.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.46 diff -u -p -r1.46 keymap.c --- keymap.c28 Nov 2011 04:41:39 - 1.46 +++ keymap.c25 Dec 2011 19:19:06 - @@ -137,7 +137,7 @@ static PF cXcar[] = { #endif /* !NO_MACRO */ setfillcol, /* f */ gotoline, /* g */ - rescan, /* h */ + markbuffer, /* h */ fileinsert, /* i */ rescan, /* j */ killbuffer_cmd, /* k */ @@ -259,7 +259,7 @@ static PF metal[] = { rescan, /* y */ rescan, /* z */ gotobop,/* { */ - rescan, /* | */ + cmdregion, /* | */ gotoeop /* } */ }; Index: mg.1 === RCS file: /home/sunil/cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.57 diff -u -p -r1.57 mg.1 --- mg.128 Nov 2011 07:58:23 - 1.57 +++ mg.125 Dec 2011 19:53:20 - @@ -196,6 +196,8 @@ call-last-kbd-macro set-fill-column .It C-x g goto-line +.It C-x h +mark-whole-buffer .It C-x i insert-file .It C-x k @@ -260,6 +262,8 @@ copy-region-as-kill execute-extended-command .It M-{ backward-paragraph +.It M-| +shell-command-on-region .It M-} forward-paragraph .It M-~ @@ -572,6 +576,9 @@ Bind a key mapping in the local (topmost Unbind a key mapping in the local (topmost) mode. .It make-backup-files Toggle generation of backup files. +.It mark-whole-buffer +Marks whole buffer as a region by putting dot at the beginning and mark +at the end of buffer. .It meta-key-mode When disabled, the meta key can be used to insert extended-ascii (8-bit) characters. @@ -734,6 +741,8 @@ Used by auto-fill-mode. Sets the mark in the current window to the current dot location. .It set-prefix-string Sets the prefix string to be used by the 'prefix-region' command. +.It shell-command-on-region +Provide the text in region to the shell command as input. .It shrink-window Shrink current window by one line. The window immediately below is expanded to pick up the slack. Index: region.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/region.c,v retrieving revision 1.29 diff -u -p -r1.29 region.c --- region.c5 Jun 2009 18:02:06 - 1.29 +++ region.c25 Dec 2011 19:38:22 - @@ -9,6 +9,8 @@ * internal use. */ +#include stdio.h + #include def.h static int getregion(struct region *); @@ -366,4 +368,66 @@ region_put_data(const char *buf, int len else linsert(1, buf[i]); } +} + +/* + * Mark whole buffer by first traversing to end-of-buffer + * and then to beginning-of-buffer. Mark, dot are implicitly + * set to eob, bob respectively during traversal. + */ +int +markbuffer(int f, int n) +{ + if (gotoeob(f,n) == FALSE) + return (FALSE); + if (gotobob(f,n) == FALSE) + return (FALSE); + return (TRUE); +} + +/* + * Pipe text from current region
Fix crash in pop-tag-mark of mg
pop-tag-mark crashes when the buffer's directory is different from mg's cwd. Steps to reproduce... generate some tags : # cd /usr/src/usr.bin/mg cvs up make make install # cd /usr/src/sys make tags use them : # mg /usr/src/sys/dev/softraid_crypto.c (for example) then M-x visit-tag-table give /usr/src/sys/arch/i386/tags put the cursor on sr_workunit then M-. which arrives at softraidvar.h and then follow scsi_xfer which puts you in scsiconf.h, then M-*, mg crashes with core dump. Record absolute filename while pushing onto stack. comments? Index: tags.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/tags.c,v retrieving revision 1.1 diff -u -p -r1.1 tags.c --- tags.c 28 Nov 2011 04:41:39 - 1.1 +++ tags.c 1 Dec 2011 19:42:09 - @@ -208,7 +208,7 @@ pushtag(char *tok) { struct ctag *res; struct tagpos *s; - char *bname; + char bname[NFILEN]; int doto, dotline; if ((res = searchtag(tok)) == NULL) @@ -216,7 +216,17 @@ pushtag(char *tok) doto = curwp-w_doto; dotline = curwp-w_dotline; - bname = curbp-b_bname; + /* record absolute filenames. Fixes issues when mg's cwd is not the +* same as buffer's directory. +*/ + if (strlcpy(bname, curbp-b_cwd, sizeof(bname)) = sizeof(bname)) { + ewprintf(filename too long); + return (FALSE); + } + if (strlcat(bname, curbp-b_bname, sizeof(bname)) = sizeof(bname)) { + ewprintf(filename too long); + return (FALSE); + } if (loadbuffer(res-fname) == FALSE) return (FALSE); @@ -227,8 +237,8 @@ pushtag(char *tok) return (FALSE); } if ((s-bname = strdup(bname)) == NULL) { - ewprintf(Out of memory); - return (FALSE); + ewprintf(Out of memory); + return (FALSE); } s-doto = doto; s-dotline = dotline;
Re: ctags(1) and mg(1) again
/sunil/cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.55 diff -u -p -r1.55 mg.1 --- mg.12 Sep 2011 02:37:52 - 1.55 +++ mg.127 Nov 2011 17:21:14 - @@ -73,6 +73,12 @@ the mark at the point of deletion. Note: The point and mark are window-specific in .Nm , not buffer-specific, as in other emacs flavours. +.Sh TAGS +.Nm +supports tags file created by +.Xr ctags 1 , +allowing user to quickly locate various object definitions. +Note that emacs uses etags, not ctags. .Sh DEFAULT KEY BINDINGS Normal editing commands are very similar to GNU Emacs. In the following examples, C-x means Control-x, and M-x means Meta-x, @@ -212,6 +218,10 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-. +find-tag +.It M-* +pop-tag-mark .It M-% query-replace .It M- @@ -461,6 +471,8 @@ If the kill fails, or is aborted, revert .It find-file-other-window Opens the specified file in a second buffer. Splits the current window if necessary. +.It find-tag +Jump to definition of tag at dot. .It forward-char Move cursor forwards (or backwards, if .Va n @@ -606,6 +618,8 @@ This command makes the previous (up the current window. There are no errors, although the command does not do a lot if there is only 1 window. +.It pop-tag-mark +Return to position where find-tag was previously invoked. .It push-shell Suspend .Nm @@ -776,6 +790,8 @@ upper case. .It upcase-word Move the cursor forward by the specified number of words. As it moves, convert any characters to upper case. +.It visit-tags-table +Record name of the tags file to be used for subsequent find-tag. .It what-cursor-position Display a bunch of useful information about the current location of dot. @@ -835,6 +851,7 @@ terminal-specific startup file concise tutorial .El .Sh SEE ALSO +.Xr ctags 1 , .Xr vi 1 .Sh CAVEATS Since it is written completely in C, there is currently no Index: tags.c === RCS file: tags.c diff -N tags.c --- /dev/null 1 Jan 1970 00:00:00 - +++ tags.c 24 Nov 2011 05:50:13 - @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2011 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h +#include sys/stat.h +#include sys/tree.h +#include sys/types.h + +#include ctype.h +#include err.h +#include stdlib.h +#include string.h +#include util.h + +#include def.h + +struct ctag; + +static int addctag(char *); +static int atbow(void); +void closetags(void); +static int ctagcmp(struct ctag *, struct ctag *); +static int curtoken(int, int, char *); +static int loadbuffer(char *); +static int loadtags(const char *); +static int pushtag(char *); +static int searchpat(char *); +static struct ctag *searchtag(char *); +static char *strip(char *, size_t); +static void unloadtags(void); + +#define MAX_TOKEN 64 +#define DEFAULTFN tags + +char *tagsfn = NULL; +int loaded = FALSE; + +/* ctags(1) entries are parsed and maintained in a tree. */ +struct ctag { + RB_ENTRY(ctag) entry; + char *tag; + char *fname; + char *pat; +}; +RB_HEAD(tagtree, ctag) tags = RB_INITIALIZER(tags); +RB_GENERATE(tagtree, ctag, entry, ctagcmp); + +struct tagpos { + SLIST_ENTRY(tagpos) entry; + intdoto; + intdotline; + char *bname; +}; +SLIST_HEAD(tagstack, tagpos) shead = SLIST_HEAD_INITIALIZER(shead); + +int +ctagcmp(struct ctag *s, struct ctag *t) +{ + return strcmp(s-tag, t-tag); +} + +/* + * Record the filename that contain tags to be used while loading them + * on first use. If a filename is already recorded, ask user to retain + * already loaded tags (if any) and unload them if user chooses not to. + */ +/* ARGSUSED */ +int +tagsvisit(int f, int n) +{ + char fname[NFILEN], *bufp, *temp; + struct stat sb; + + if (getbufcwd(fname, sizeof(fname)) == FALSE) + fname[0] = '\0'; + + if (strlcat(fname, DEFAULTFN, sizeof(fname)) = sizeof(fname)) { + ewprintf(Filename too long); + return (FALSE); + } + + bufp
Re: ctags(1) and mg(1) again
); } return (TRUE); Index: mg.1 === RCS file: /home/sunil/cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.55 diff -u -p -r1.55 mg.1 --- mg.12 Sep 2011 02:37:52 - 1.55 +++ mg.118 Nov 2011 06:25:09 - @@ -212,6 +212,10 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-. +find-tag +.It M-* +pop-tag-mark .It M-% query-replace .It M- @@ -461,6 +465,8 @@ If the kill fails, or is aborted, revert .It find-file-other-window Opens the specified file in a second buffer. Splits the current window if necessary. +.It find-tag +Jump to definition of tag at dot. .It forward-char Move cursor forwards (or backwards, if .Va n @@ -606,6 +612,8 @@ This command makes the previous (up the current window. There are no errors, although the command does not do a lot if there is only 1 window. +.It pop-tag-mark +Return to position where find-tag was previously invoked. .It push-shell Suspend .Nm @@ -776,6 +784,8 @@ upper case. .It upcase-word Move the cursor forward by the specified number of words. As it moves, convert any characters to upper case. +.It visit-tags-table +Record name of the tags file to be used for subsequent find-tag. .It what-cursor-position Display a bunch of useful information about the current location of dot. @@ -835,6 +845,7 @@ terminal-specific startup file concise tutorial .El .Sh SEE ALSO +.Xr ctags 1 , .Xr vi 1 .Sh CAVEATS Since it is written completely in C, there is currently no @@ -846,3 +857,8 @@ In order to use 8-bit characters (such a needs to be disabled via the .Dq meta-key-mode command. +.Pp +Unlike emacs which uses etags, +.Nm +can only understand tags generated by +.Xr ctags 1 . Index: tags.c === RCS file: tags.c diff -N tags.c --- /dev/null 1 Jan 1970 00:00:00 - +++ tags.c 24 Nov 2011 05:50:13 - @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2011 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h +#include sys/stat.h +#include sys/tree.h +#include sys/types.h + +#include ctype.h +#include err.h +#include stdlib.h +#include string.h +#include util.h + +#include def.h + +struct ctag; + +static int addctag(char *); +static int atbow(void); +void closetags(void); +static int ctagcmp(struct ctag *, struct ctag *); +static int curtoken(int, int, char *); +static int loadbuffer(char *); +static int loadtags(const char *); +static int pushtag(char *); +static int searchpat(char *); +static struct ctag *searchtag(char *); +static char *strip(char *, size_t); +static void unloadtags(void); + +#define MAX_TOKEN 64 +#define DEFAULTFN tags + +char *tagsfn = NULL; +int loaded = FALSE; + +/* ctags(1) entries are parsed and maintained in a tree. */ +struct ctag { + RB_ENTRY(ctag) entry; + char *tag; + char *fname; + char *pat; +}; +RB_HEAD(tagtree, ctag) tags = RB_INITIALIZER(tags); +RB_GENERATE(tagtree, ctag, entry, ctagcmp); + +struct tagpos { + SLIST_ENTRY(tagpos) entry; + intdoto; + intdotline; + char *bname; +}; +SLIST_HEAD(tagstack, tagpos) shead = SLIST_HEAD_INITIALIZER(shead); + +int +ctagcmp(struct ctag *s, struct ctag *t) +{ + return strcmp(s-tag, t-tag); +} + +/* + * Record the filename that contain tags to be used while loading them + * on first use. If a filename is already recorded, ask user to retain + * already loaded tags (if any) and unload them if user chooses not to. + */ +/* ARGSUSED */ +int +tagsvisit(int f, int n) +{ + char fname[NFILEN], *bufp, *temp; + struct stat sb; + + if (getbufcwd(fname, sizeof(fname)) == FALSE) + fname[0] = '\0'; + + if (strlcat(fname, DEFAULTFN, sizeof(fname)) = sizeof(fname)) { + ewprintf(Filename too long); + return (FALSE); + } + + bufp = eread(visit tags table (default %s): , fname, + NFILEN, EFFILE | EFCR | EFNEW | EFDEF, DEFAULTFN); + + if (stat(bufp, sb
Re: ctags(1) and mg(1) again
); Index: mg.1 === RCS file: /home/sunil/cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.55 diff -u -p -r1.55 mg.1 --- mg.12 Sep 2011 02:37:52 - 1.55 +++ mg.112 Nov 2011 19:40:13 - @@ -212,6 +212,10 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-. +find-tag +.It M-* +pop-tag .It M-% query-replace .It M- @@ -461,6 +465,8 @@ If the kill fails, or is aborted, revert .It find-file-other-window Opens the specified file in a second buffer. Splits the current window if necessary. +.It find-tag +Jump to definition of tag at dot. .It forward-char Move cursor forwards (or backwards, if .Va n @@ -606,6 +612,8 @@ This command makes the previous (up the current window. There are no errors, although the command does not do a lot if there is only 1 window. +.It pop-tag +Return to position where find-tag was previously invoked. .It push-shell Suspend .Nm @@ -776,6 +784,8 @@ upper case. .It upcase-word Move the cursor forward by the specified number of words. As it moves, convert any characters to upper case. +.It visit-tags-file +Record name of the tags file to be used for subsequent find-tag. .It what-cursor-position Display a bunch of useful information about the current location of dot. @@ -835,6 +845,7 @@ terminal-specific startup file concise tutorial .El .Sh SEE ALSO +.Xr ctags 1 , .Xr vi 1 .Sh CAVEATS Since it is written completely in C, there is currently no @@ -846,3 +857,8 @@ In order to use 8-bit characters (such a needs to be disabled via the .Dq meta-key-mode command. +.Pp +Unlike emacs which uses etags, +.Nm +can only understand tags generated by +.Xr ctags 1 . Index: tags.c === RCS file: tags.c diff -N tags.c --- /dev/null 1 Jan 1970 00:00:00 - +++ tags.c 15 Nov 2011 04:02:53 - @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2011 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h +#include sys/tree.h +#include sys/types.h + +#include ctype.h +#include err.h +#include stdlib.h +#include string.h +#include util.h + +#include def.h + +struct ctag; + +static int addctag(char *); +static int atbow(void); +void closetags(void); +static int ctagcmp(struct ctag *, struct ctag *); +static int curtoken(int, int, char *); +static int loadbuffer(char *); +static int loadtags(const char *); +static int pushtag(char *); +static int searchpat(char *); +static struct ctag *searchtag(char *); +static char *strip(char *, size_t); +static void unloadtags(void); + +#define MAX_TOKEN 64 +#define DEFAULTFN tags + +char *tagsfn = NULL; +int loaded = FALSE; + +/* ctags(1) entries are parsed and maintained in a tree. */ +struct ctag { + RB_ENTRY(ctag) entry; + char *tag; + char *fname; + char *pat; +}; +RB_HEAD(tagtree, ctag) tags = RB_INITIALIZER(tags); +RB_GENERATE(tagtree, ctag, entry, ctagcmp); + +struct tagpos { + SLIST_ENTRY(tagpos) entry; + intdoto; + intdotline; + char *bname; +}; +SLIST_HEAD(tagstack, tagpos) shead = SLIST_HEAD_INITIALIZER(shead); + +int +ctagcmp(struct ctag *s, struct ctag *t) +{ + return strcmp(s-tag, t-tag); +} + +/* + * Record the filename that contain tags to be used while loading them + * on first use. If a filename is already recorded, ask user to retain + * already loaded tags (if any) and unload them if user chooses not to. + */ +/* ARGSUSED */ +int +tagsvisit(int f, int n) +{ + char fname[NFILEN], *bufp, *temp; + + if (getbufcwd(fname, sizeof(fname)) == FALSE) + fname[0] = '\0'; + + if (strlcat(fname, DEFAULTFN, sizeof(fname)) = sizeof(fname)) { + ewprintf(Filename too long); + return (FALSE); + } + + bufp = eread(visit tags table (default %s): , fname, + NFILEN, EFNEW | EFCR | EFFILE | EFDEF, DEFAULTFN); + + if (tagsfn == NULL) { + if (bufp == NULL) + return (ABORT
Re: ctags(1) and mg(1) again
; /* Full. */ } +extern void tags_close(void); /* * Quit command. If an argument, always quit. Otherwise confirm if a buffer * has been changed and not written out. Normally bound to C-X C-C. @@ -235,6 +238,7 @@ quit(int f, int n) #ifdef SYSCLEANUP SYSCLEANUP; #endif /* SYSCLEANUP */ + tags_close(); exit(GOOD); } return (TRUE); Index: mg.1 === RCS file: /home/sunil/cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.55 diff -u -p -r1.55 mg.1 --- mg.12 Sep 2011 02:37:52 - 1.55 +++ mg.127 Oct 2011 18:18:27 - @@ -212,6 +212,10 @@ suspend-emacs scroll-other-window .It M-SPC just-one-space +.It M-. +push-tag +.It M-* +pop-tag .It M-% query-replace .It M- @@ -606,10 +610,14 @@ This command makes the previous (up the current window. There are no errors, although the command does not do a lot if there is only 1 window. +.It pop-tag +Return to position where push-tag was previously invoked. .It push-shell Suspend .Nm and switch to alternate screen, if available. +.It push-tag +Jump to definition of tag at dot. .It pwd Display current (global) working directory in the status area. .It query-replace @@ -835,6 +843,7 @@ terminal-specific startup file concise tutorial .El .Sh SEE ALSO +.Xr ctags 1 , .Xr vi 1 .Sh CAVEATS Since it is written completely in C, there is currently no Index: tags.c === RCS file: tags.c diff -N tags.c --- /dev/null 1 Jan 1970 00:00:00 - +++ tags.c 7 Nov 2011 17:47:24 - @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2011 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h +#include sys/tree.h +#include sys/types.h + +#include err.h +#include stdio.h +#include stdlib.h +#include string.h +#include util.h + +#include def.h + +#define MAX_TOKEN 63 + +struct ctag; + +void tags_init(); +void tags_close(); +static void addctag(char *); +static int curtoken(int, int, char *); +static struct ctag *findtag(int, int); +static int loadbuffer(char *); +static int patsearch(char *); +static char *strip(char *, size_t); + +/* ctags(1) entries are parsed and maintained in a tree. */ +struct ctag { + RB_ENTRY(ctag) entry; + char *tag; + char *fname; + char *pat; +}; + +static int +ctagcmp(struct ctag *s, struct ctag *t) +{ + return strcmp(s-tag, t-tag); +} + +RB_HEAD(tagtree, ctag) tags = RB_INITIALIZER(tags); +RB_GENERATE(tagtree, ctag, entry, ctagcmp); + +struct tagpos { + SLIST_ENTRY(tagpos) entry; + struct line *dotp; + intdoto; + intdotline; + char *bfname; +}; + +/* The stack used by pushtag and poptag. */ +SLIST_HEAD(tagstack, tagpos) shead = SLIST_HEAD_INITIALIZER(shead); + +/* + * Lookup current word at dot in tagstree. If an entry is found record + * the current dot location, load the file and position the new dot at + * the pattern in the file. +*/ +/*ARGSUSED */ +int +pushtag(int f, int n) +{ + struct ctag *res; + struct tagpos *s; + char *bfname; + struct line *dotp; + int doto; + int dotline; + + if ((res = findtag(f, n)) == NULL) + return (FALSE); + + dotp = curwp-w_dotp; + doto = curwp-w_doto; + dotline = curwp-w_dotline; + bfname = curbp-b_fname; + + if (loadbuffer(res-fname) == FALSE) + return (FALSE); + + if (patsearch(res-pat) == TRUE) { + if ((s = malloc(sizeof(struct tagpos))) == NULL) + err(1, NULL); + if ((s-bfname = strdup(bfname)) == NULL) + err(1, NULL); + s-dotp = dotp; + s-doto = doto; + s-dotline = dotline; + SLIST_INSERT_HEAD(shead, s, entry); + return (TRUE); + } else { + ewprintf(%s: pattern not found, res-tag); + return (FALSE); + } + return (FALSE); +} + +/* + * If tag
Re: ctags(1) and mg(1) again
The new file tags.c now has a proper license. Could you please review this new diff. Index: Makefile === RCS file: /home/sunil/cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.24 diff -u -p -r1.24 Makefile --- Makefile2 Feb 2011 05:21:36 - 1.24 +++ Makefile9 Oct 2011 20:19:43 - @@ -2,7 +2,7 @@ PROG= mg -LDADD+=-lcurses +LDADD+=-lcurses -lutil DPADD+=${LIBCURSES} # (Common) compile-time options: @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c theo.c +SRCS+= cmode.c dired.c grep.c tags.c theo.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: def.h === RCS file: /home/sunil/cvs/src/usr.bin/mg/def.h,v retrieving revision 1.116 diff -u -p -r1.116 def.h --- def.h 23 Jan 2011 00:45:03 - 1.116 +++ def.h 8 Oct 2011 12:07:18 - @@ -515,6 +515,10 @@ int space_to_tabstop(int, int); int backtoindent(int, int); int joinline(int, int); +/* tags.c X */ +int pushtag(int, int); +int poptag(int, int); + /* extend.c X */ int insert(int, int); int bindtokey(int, int); Index: keymap.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.45 diff -u -p -r1.45 keymap.c --- keymap.c18 Jan 2011 16:25:40 - 1.45 +++ keymap.c9 Oct 2011 20:23:08 - @@ -204,8 +204,11 @@ static PF metapct[] = { }; static PF metami[] = { + poptag, /* * */ + rescan, /* + */ + rescan, /* , */ negative_argument, /* - */ - rescan, /* . */ + pushtag,/* . */ rescan, /* / */ digit_argument, /* 0 */ digit_argument, /* 1 */ @@ -298,7 +301,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { '%', '%', metapct, NULL }, { - '-', '', metami, NULL + '*', '', metami, NULL }, { '[', 'f', metasqf, (KEYMAP *) metasqlmap Index: main.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/main.c,v retrieving revision 1.61 diff -u -p -r1.61 main.c --- main.c 4 Jun 2009 02:23:37 - 1.61 +++ main.c 9 Oct 2011 15:05:40 - @@ -77,11 +77,13 @@ main(int argc, char **argv) extern void theo_init(void); extern void cmode_init(void); extern void dired_init(void); - + extern void tags_init(void); + dired_init(); grep_init(); theo_init(); cmode_init(); + tags_init(); } if (init_fcn_name @@ -217,6 +219,7 @@ edinit(PF init_fcn) wp-w_rflag = WFMODE | WFFULL; /* Full. */ } +extern void tags_close(void); /* * Quit command. If an argument, always quit. Otherwise confirm if a buffer * has been changed and not written out. Normally bound to C-X C-C. @@ -235,6 +238,7 @@ quit(int f, int n) #ifdef SYSCLEANUP SYSCLEANUP; #endif /* SYSCLEANUP */ + tags_close(); exit(GOOD); } return (TRUE); Index: tags.c === RCS file: tags.c diff -N tags.c --- /dev/null 1 Jan 1970 00:00:00 - +++ tags.c 13 Oct 2011 17:38:24 - @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2011 Sunil Nimmagadda su...@sunilnimmagadda.com + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include sys/queue.h +#include sys/tree.h +#include sys/types.h + +#include err.h +#include stdio.h +#include stdlib.h +#include string.h +#include util.h + +#include def.h + +#define MAX_TOKEN 63 + +struct ctag; + +static void addctag(char *); +static int curtoken(int, int, char
ctags(1) and mg(1) again
Hello, This time a little smaller and a simplified diff. A brief outline of what it does... 1) During mg startup it checks and loads a file named tags in pwd. 2) M-. would jump to the definition of identifier under cursor if it has an entry in tags file. 3) MS-* pops back to the location before the jump. tags file is of the format... tag\tfilename\tpattern\n The pattern in tags entry could be any of the following formats... /^$/ ?^$? /^/ ?^? with the / character escaped with a \. This diff strips off the special characters at beginning, trailing of the pattern and removes escape characters so that pattern matching would be a simple strncmp. Comments most welcome. Index: Makefile === RCS file: /home/sunil/cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.24 diff -u -p -r1.24 Makefile --- Makefile2 Feb 2011 05:21:36 - 1.24 +++ Makefile9 Oct 2011 20:19:43 - @@ -2,7 +2,7 @@ PROG= mg -LDADD+=-lcurses +LDADD+=-lcurses -lutil DPADD+=${LIBCURSES} # (Common) compile-time options: @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c theo.c +SRCS+= cmode.c dired.c grep.c tags.c theo.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: def.h === RCS file: /home/sunil/cvs/src/usr.bin/mg/def.h,v retrieving revision 1.116 diff -u -p -r1.116 def.h --- def.h 23 Jan 2011 00:45:03 - 1.116 +++ def.h 8 Oct 2011 12:07:18 - @@ -515,6 +515,10 @@ int space_to_tabstop(int, int); int backtoindent(int, int); int joinline(int, int); +/* tags.c X */ +int pushtag(int, int); +int poptag(int, int); + /* extend.c X */ int insert(int, int); int bindtokey(int, int); Index: keymap.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.45 diff -u -p -r1.45 keymap.c --- keymap.c18 Jan 2011 16:25:40 - 1.45 +++ keymap.c9 Oct 2011 20:23:08 - @@ -204,8 +204,11 @@ static PF metapct[] = { }; static PF metami[] = { + poptag, /* * */ + rescan, /* + */ + rescan, /* , */ negative_argument, /* - */ - rescan, /* . */ + pushtag,/* . */ rescan, /* / */ digit_argument, /* 0 */ digit_argument, /* 1 */ @@ -298,7 +301,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { '%', '%', metapct, NULL }, { - '-', '', metami, NULL + '*', '', metami, NULL }, { '[', 'f', metasqf, (KEYMAP *) metasqlmap Index: main.c === RCS file: /home/sunil/cvs/src/usr.bin/mg/main.c,v retrieving revision 1.61 diff -u -p -r1.61 main.c --- main.c 4 Jun 2009 02:23:37 - 1.61 +++ main.c 9 Oct 2011 15:05:40 - @@ -77,11 +77,13 @@ main(int argc, char **argv) extern void theo_init(void); extern void cmode_init(void); extern void dired_init(void); - + extern void tags_init(void); + dired_init(); grep_init(); theo_init(); cmode_init(); + tags_init(); } if (init_fcn_name @@ -217,6 +219,7 @@ edinit(PF init_fcn) wp-w_rflag = WFMODE | WFFULL; /* Full. */ } +extern void tags_close(void); /* * Quit command. If an argument, always quit. Otherwise confirm if a buffer * has been changed and not written out. Normally bound to C-X C-C. @@ -235,6 +238,7 @@ quit(int f, int n) #ifdef SYSCLEANUP SYSCLEANUP; #endif /* SYSCLEANUP */ + tags_close(); exit(GOOD); } return (TRUE); Index: tags.c === RCS file: tags.c diff -N tags.c --- /dev/null 1 Jan 1970 00:00:00 - +++ tags.c 9 Oct 2011 20:26:09 - @@ -0,0 +1,306 @@ +/* This file is in public domain. */ + +#include sys/queue.h +#include sys/tree.h +#include sys/types.h + +#include err.h +#include stdio.h +#include stdlib.h +#include string.h +#include util.h + +#include def.h + +#define MAX_TOKEN 63 + +struct ctag; + +static void addctag(char *); +static int curtoken(int, int, char *); +static struct ctag *findtag(int, int); +static int loadbuffer(char *); +static int patsearch(char *); +static char
Re: ctags(1) and mg
On Fri, Sep 02, 2011 at 10:17:02AM -0700, Matthew Dempsky wrote: On Fri, Sep 2, 2011 at 8:55 AM, Sunil Nimmagadda su...@sunilnimmagadda.com wrote: This diff adds tags support to Mg. I am NOT an emacs user so if this combination is a bit odd then please excuse. It parses the tags file generated by ctags(1) and maintains a tree. M-. on first character of a word jumps to it's definition and M-* jumps back to previous location. I'd love to have ctags support in mg. -# $OpenBSD: Makefile,v 1.24 2011/02/02 05:21:36 lum Exp $ +# $OpenBSD: Makefile,v 1.23 2011/01/18 17:35:42 lum Exp $ Can you recreate the diff without these changes? +/* + * Helper function to append a character to a C string. + */ +static void +append(char *s, int c) +{ + ? ? ? ?size_t l = strlen(s); + ? ? ? s[l++] = c; + ? ? ? s[l] = '\0'; +} I don't like this. I don't see any evidence that the length of s here will be bounded, and it appears to be used to fill a local fixed-sized buffer. Having to call strlen() for each character append is suboptimal too. Means building up the string takes O(n^2) time. (I haven't had a chance to look at the diff in depth yet, but this issue stood out to me.) Being a little less stupid this time. Rewrote the string handling part, style(9) formatting and refactored pushtag function. Mg and emacs unlike nvi don't consider '_' as inword i.e., if you forward-word on tags_init, the cursor is positioned at '_' instead of at the end of the word. This causes lookup on identifiers with '_ fail. The cinfo.c part of following diff fixes this. I am not sure if this offends mg users. I will take back cinfo.c changes if its wrong to do so. Index: Makefile === RCS file: /cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.24 diff -u -p -r1.24 Makefile --- Makefile2 Feb 2011 05:21:36 - 1.24 +++ Makefile3 Sep 2011 11:39:41 - @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c theo.c +SRCS+= cmode.c dired.c grep.c theo.c tags.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: cinfo.c === RCS file: /cvs/src/usr.bin/mg/cinfo.c,v retrieving revision 1.15 diff -u -p -r1.15 cinfo.c --- cinfo.c 13 Dec 2005 06:01:27 - 1.15 +++ cinfo.c 3 Sep 2011 11:39:41 - @@ -43,7 +43,7 @@ const char cinfo[256] = { _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, /* 0x5X */ _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, _MG_U | _MG_W, 0, - 0, 0, 0, 0, + 0, 0, 0, _MG_W, 0, _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, /* 0x6X */ _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, _MG_L | _MG_W, Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.116 diff -u -p -r1.116 def.h --- def.h 23 Jan 2011 00:45:03 - 1.116 +++ def.h 3 Sep 2011 11:39:41 - @@ -514,6 +514,10 @@ int backdel(int, int); int space_to_tabstop(int, int); int backtoindent(int, int); int joinline(int, int); + +/* tags.c X */ +int pushtag(int, int); +int poptag(int, int); /* extend.c X */ int insert(int, int); Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.45 diff -u -p -r1.45 keymap.c --- keymap.c18 Jan 2011 16:25:40 - 1.45 +++ keymap.c3 Sep 2011 11:39:42 - @@ -204,8 +204,11 @@ static PF metapct[] = { }; static PF metami[] = { + poptag, /* * */ + rescan, /* + */ + rescan, /* , */ negative_argument, /* - */ - rescan, /* . */ + pushtag,/* . */ rescan, /* / */ digit_argument, /* 0 */ digit_argument, /* 1 */ @@ -231,7 +234,7 @@ static PF metasqf[] = { joinline, /* ^ */ rescan, /* _ */ rescan, /* ` */ - rescan, /* a */ + rescan, /* a */ backword, /* b */ capword,/* c */ delfword, /* d */ @@ -298,7 +301,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { '%', '%', metapct, NULL }, { - '-', '', metami, NULL + '*', '', metami, NULL }, { '[', 'f', metasqf
Re: ctags(1) and mg
On Sat, Sep 03, 2011 at 07:12:40PM +0300, Henri Kemppainen wrote: Being a little less stupid this time. Rewrote the string handling part, style(9) formatting and refactored pushtag function. Some thoughts about this. Are you sure you're not going to overflow t in re_tag_conv when you insert escapes? Correct me if I'm wrong, but I think ctags patterns aren't really regexes (which is why you're playing with escapes, and stripping re-inserting magic) -- wouldn't it be easier to do the matching in a plain loop, checking the start/end offsets against bol/eol if the magic anchors were present? The assumption in ex is that t is of double the size of s so that there is enough room to insert escapes in the worst case if every character needs to be escaped. Yes, t should be of size NLINE * 2 + 1. Plain loop matching would work provided ctags(1) doesn't escape every / with a \. I have a earlier diff which does this simple char to char comparsion but it failed with these backslashes and that is when I looked at ex code and I felt it much cleaner than rolling my own. Oh and I almost forgot lines in mg aren't NUL terminated. Second, it seems you're allocating a number of strings in addctag. This isn't technically wrong, but one of the upsides of NUL-terminated strings is that you can split one into many (as strsep does) without messing with multiple buffers allocs frees. Yes, that is possible and never crossed my mind. Will try to come up with a new diff. I'd supplement ctagnode with a flag field to tell which magic anchors were present originally. I'd actually strip all the magic and backslashes in addctag, such that pattern pointed to by pat is simply a plain string which must exactly match what's in the buffer, character by character -- making the match loop I proposed above a trivial one. Finally, the choice to use underscores in the name of one function stands out as a little bit odd ;-) I am trying to be consistent with names here, all init methods were indeed named _init. That's what I got at a quick glance. I'll try give it another look once this fever and headache fade. get well soon :)
ctags(1) and mg
Hello, This diff adds tags support to Mg. I am NOT an emacs user so if this combination is a bit odd then please excuse. It parses the tags file generated by ctags(1) and maintains a tree. M-. on first character of a word jumps to it's definition and M-* jumps back to previous location. Index: Makefile === RCS file: /cvs/src/usr.bin/mg/Makefile,v retrieving revision 1.24 diff -u -p -r1.24 Makefile --- Makefile2 Feb 2011 05:21:36 - 1.24 +++ Makefile2 Sep 2011 15:00:39 - @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.24 2011/02/02 05:21:36 lum Exp $ +# $OpenBSD: Makefile,v 1.23 2011/01/18 17:35:42 lum Exp $ PROG= mg @@ -24,7 +24,7 @@ SRCS= autoexec.c basic.c buffer.c cinfo. # # More or less standalone extensions. # -SRCS+= cmode.c dired.c grep.c theo.c +SRCS+= cmode.c dired.c grep.c theo.c tags.c afterinstall: ${INSTALL} -d ${DESTDIR}${DOCDIR}/mg Index: buffer.c === RCS file: /cvs/src/usr.bin/mg/buffer.c,v retrieving revision 1.77 diff -u -p -r1.77 buffer.c --- buffer.c23 Jan 2011 00:45:03 - 1.77 +++ buffer.c2 Sep 2011 15:00:39 - @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.77 2011/01/23 00:45:03 kjell Exp $ */ +/* $OpenBSD: buffer.c,v 1.76 2011/01/21 19:10:13 kjell Exp $ */ /* This file is in the public domain. */ Index: def.h === RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.116 diff -u -p -r1.116 def.h --- def.h 23 Jan 2011 00:45:03 - 1.116 +++ def.h 2 Sep 2011 15:00:39 - @@ -1,4 +1,4 @@ -/* $OpenBSD: def.h,v 1.116 2011/01/23 00:45:03 kjell Exp $ */ +/* $OpenBSD: def.h,v 1.115 2011/01/18 16:25:40 kjell Exp $ */ /* This file is in the public domain. */ @@ -514,6 +514,10 @@ int backdel(int, int); int space_to_tabstop(int, int); int backtoindent(int, int); int joinline(int, int); + +/* tags.c X */ +int pushtag(int, int); +int poptag(int, int); /* extend.c X */ int insert(int, int); Index: keymap.c === RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.45 diff -u -p -r1.45 keymap.c --- keymap.c18 Jan 2011 16:25:40 - 1.45 +++ keymap.c2 Sep 2011 15:00:40 - @@ -1,4 +1,4 @@ -/* $OpenBSD: keymap.c,v 1.45 2011/01/18 16:25:40 kjell Exp $ */ +/* $OpenBSD: keymap.c,v 1.44 2011/01/17 03:12:06 kjell Exp $ */ /* This file is in the public domain. */ @@ -204,8 +204,11 @@ static PF metapct[] = { }; static PF metami[] = { + poptag, /* * */ + rescan, /* + */ + rescan, /* , */ negative_argument, /* - */ - rescan, /* . */ + pushtag,/* . */ rescan, /* / */ digit_argument, /* 0 */ digit_argument, /* 1 */ @@ -231,7 +234,7 @@ static PF metasqf[] = { joinline, /* ^ */ rescan, /* _ */ rescan, /* ` */ - rescan, /* a */ + rescan, /* a */ backword, /* b */ capword,/* c */ delfword, /* d */ @@ -298,7 +301,7 @@ struct KEYMAPE (8 + IMAPEXT) metamap = { '%', '%', metapct, NULL }, { - '-', '', metami, NULL + '*', '', metami, NULL }, { '[', 'f', metasqf, (KEYMAP *) metasqlmap Index: main.c === RCS file: /cvs/src/usr.bin/mg/main.c,v retrieving revision 1.61 diff -u -p -r1.61 main.c --- main.c 4 Jun 2009 02:23:37 - 1.61 +++ main.c 2 Sep 2011 15:00:40 - @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.61 2009/06/04 02:23:37 kjell Exp $ */ +/* $OpenBSD: main.c,v 1.60 2008/06/13 18:51:02 kjell Exp $ */ /* This file is in the public domain. */ @@ -77,11 +77,13 @@ main(int argc, char **argv) extern void theo_init(void); extern void cmode_init(void); extern void dired_init(void); - + extern void tags_init(void); + dired_init(); grep_init(); theo_init(); cmode_init(); + tags_init(); } if (init_fcn_name @@ -217,6 +219,7 @@ edinit(PF init_fcn) wp-w_rflag = WFMODE | WFFULL; /* Full. */ } +extern void tags_close(void); /* * Quit command. If an argument, always quit. Otherwise confirm if a buffer * has