ftp(1): tls_close(3) handle TLS_WANT_POLLIN, TLS_WANT_PLLOUT

2017-03-01 Thread Sunil Nimmagadda
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

2017-03-01 Thread Sunil Nimmagadda

Theo de Raadt  writes:

>> > 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

2017-03-01 Thread Sunil Nimmagadda

Stuart Henderson  writes:

> 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

2016-11-22 Thread Sunil Nimmagadda

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

2016-11-21 Thread Sunil Nimmagadda

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

2016-09-07 Thread Sunil Nimmagadda
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.

2016-09-04 Thread Sunil Nimmagadda
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="/:..."

2016-01-19 Thread Sunil Nimmagadda
> 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

2015-12-19 Thread Sunil Nimmagadda
> 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

2015-12-08 Thread Sunil Nimmagadda
> 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)

2015-08-17 Thread Sunil Nimmagadda
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)

2015-08-17 Thread Sunil Nimmagadda
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

2015-08-15 Thread Sunil Nimmagadda
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

2015-06-01 Thread Sunil Nimmagadda
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

2015-05-21 Thread Sunil Nimmagadda
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)

2015-05-03 Thread Sunil Nimmagadda
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)

2015-04-23 Thread Sunil Nimmagadda
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)

2015-04-16 Thread Sunil Nimmagadda
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

2014-12-23 Thread Sunil Nimmagadda
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

2014-01-07 Thread Sunil Nimmagadda
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

2013-07-12 Thread Sunil Nimmagadda
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

2013-07-10 Thread Sunil Nimmagadda
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

2012-06-28 Thread Sunil Nimmagadda
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

2012-05-30 Thread Sunil Nimmagadda
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

2012-04-10 Thread Sunil Nimmagadda
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

2012-03-27 Thread Sunil Nimmagadda
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

2012-03-18 Thread Sunil Nimmagadda
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

2012-03-11 Thread Sunil Nimmagadda
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

2012-02-29 Thread Sunil Nimmagadda
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

2012-02-22 Thread Sunil Nimmagadda
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

2011-12-25 Thread Sunil Nimmagadda
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

2011-12-01 Thread Sunil Nimmagadda
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

2011-11-27 Thread Sunil Nimmagadda
/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

2011-11-23 Thread Sunil Nimmagadda
);
}
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

2011-11-14 Thread Sunil Nimmagadda
);
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

2011-11-07 Thread Sunil Nimmagadda
;  /* 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

2011-10-13 Thread Sunil Nimmagadda
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

2011-10-09 Thread Sunil Nimmagadda
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

2011-09-03 Thread Sunil Nimmagadda
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

2011-09-03 Thread Sunil Nimmagadda
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

2011-09-02 Thread Sunil Nimmagadda
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