* ext/socket/socket.c (make_hostent): fix memory leak, based on

the patch from HORIKAWA Hisashi <vzw00011@nifty.ne.jp>.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6065 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2004-04-01 23:13:39 +00:00
parent b9e7165e78
commit 64ec09d456
3 changed files with 203 additions and 268 deletions

View File

@ -1,3 +1,8 @@
Fri Apr 2 07:31:38 2004 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/socket/socket.c (make_hostent): fix memory leak, based on
the patch from HORIKAWA Hisashi <vzw00011@nifty.ne.jp>.
Thu Apr 1 19:58:37 2004 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp> Thu Apr 1 19:58:37 2004 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>
* lib/soap/mapping/{factory.rb,registry.rb}: fixed illegal mapped URI * lib/soap/mapping/{factory.rb,registry.rb}: fixed illegal mapped URI

View File

@ -65,7 +65,6 @@
#include "sockport.h" #include "sockport.h"
static int do_not_reverse_lookup = 0; static int do_not_reverse_lookup = 0;
#define FMODE_NOREVLOOKUP 0x100
VALUE rb_cBasicSocket; VALUE rb_cBasicSocket;
VALUE rb_cIPSocket; VALUE rb_cIPSocket;
@ -179,9 +178,6 @@ init_sock(sock, fd)
fp->f = rb_fdopen(fd, "r"); fp->f = rb_fdopen(fd, "r");
fp->f2 = rb_fdopen(fd, "w"); fp->f2 = rb_fdopen(fd, "w");
fp->mode = FMODE_READWRITE; fp->mode = FMODE_READWRITE;
if (do_not_reverse_lookup) {
fp->mode |= FMODE_NOREVLOOKUP;
}
rb_io_synchronized(fp); rb_io_synchronized(fp);
return sock; return sock;
@ -396,35 +392,7 @@ bsock_send(argc, argv, sock)
return INT2FIX(n); return INT2FIX(n);
} }
static VALUE static VALUE ipaddr _((struct sockaddr*));
bsock_do_not_reverse_lookup(sock)
VALUE sock;
{
OpenFile *fptr;
GetOpenFile(sock, fptr);
return (fptr->mode & FMODE_NOREVLOOKUP) ? Qtrue : Qfalse;
}
static VALUE
bsock_do_not_reverse_lookup_set(sock, state)
VALUE sock;
VALUE state;
{
OpenFile *fptr;
rb_secure(4);
GetOpenFile(sock, fptr);
if (RTEST(state)) {
fptr->mode |= FMODE_NOREVLOOKUP;
}
else {
fptr->mode &= ~FMODE_NOREVLOOKUP;
}
return sock;
}
static VALUE ipaddr _((struct sockaddr*, int));
#ifdef HAVE_SYS_UN_H #ifdef HAVE_SYS_UN_H
static VALUE unixaddr _((struct sockaddr_un*)); static VALUE unixaddr _((struct sockaddr_un*));
#endif #endif
@ -492,7 +460,7 @@ s_recvfrom(sock, argc, argv, from)
rb_raise(rb_eTypeError, "sockaddr size differs - should not happen"); rb_raise(rb_eTypeError, "sockaddr size differs - should not happen");
} }
#endif #endif
return rb_assoc_new(str, ipaddr((struct sockaddr*)buf, fptr->mode & FMODE_NOREVLOOKUP)); return rb_assoc_new(str, ipaddr((struct sockaddr*)buf));
#ifdef HAVE_SYS_UN_H #ifdef HAVE_SYS_UN_H
case RECV_UNIX: case RECV_UNIX:
return rb_assoc_new(str, unixaddr((struct sockaddr_un*)buf)); return rb_assoc_new(str, unixaddr((struct sockaddr_un*)buf));
@ -528,15 +496,6 @@ bsock_do_not_rev_lookup_set(self, val)
return val; return val;
} }
static void
raise_socket_error(reason, error)
char *reason;
int error;
{
if (error == EAI_SYSTEM) rb_sys_fail(reason);
rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
}
static void static void
make_ipaddr0(addr, buf, len) make_ipaddr0(addr, buf, len)
struct sockaddr *addr; struct sockaddr *addr;
@ -547,7 +506,7 @@ make_ipaddr0(addr, buf, len)
error = getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0, NI_NUMERICHOST); error = getnameinfo(addr, SA_LEN(addr), buf, len, NULL, 0, NI_NUMERICHOST);
if (error) { if (error) {
raise_socket_error("getnameinfo", error); rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error));
} }
} }
@ -666,7 +625,8 @@ sock_addrinfo(host, port, socktype, flags)
VALUE host, port; VALUE host, port;
int socktype, flags; int socktype, flags;
{ {
struct addrinfo hints, *hintsp, *res; struct addrinfo hints;
struct addrinfo* res = NULL;
char *hostp, *portp; char *hostp, *portp;
int error; int error;
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
@ -678,18 +638,16 @@ sock_addrinfo(host, port, socktype, flags)
socktype = SOCK_DGRAM; socktype = SOCK_DGRAM;
} }
hintsp = &hints;
MEMZERO(&hints, struct addrinfo, 1); MEMZERO(&hints, struct addrinfo, 1);
hints.ai_family = PF_UNSPEC; hints.ai_family = AF_UNSPEC;
hints.ai_protocol = 0;
hints.ai_socktype = socktype; hints.ai_socktype = socktype;
hints.ai_flags = flags; hints.ai_flags = flags;
error = getaddrinfo(hostp, portp, hintsp, &res); error = getaddrinfo(hostp, portp, &hints, &res);
if (error) { if (error) {
if (hostp && hostp[strlen(hostp)-1] == '\n') { if (hostp && hostp[strlen(hostp)-1] == '\n') {
rb_raise(rb_eSocket, "newline at the end of hostname"); rb_raise(rb_eSocket, "newline at the end of hostname");
} }
raise_socket_error("getaddrinfo", error); rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error));
} }
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
@ -713,9 +671,8 @@ sock_addrinfo(host, port, socktype, flags)
} }
static VALUE static VALUE
ipaddr(sockaddr, norevlookup) ipaddr(sockaddr)
struct sockaddr *sockaddr; struct sockaddr *sockaddr;
int norevlookup;
{ {
VALUE family, port, addr1, addr2; VALUE family, port, addr1, addr2;
VALUE ary; VALUE ary;
@ -748,22 +705,21 @@ ipaddr(sockaddr, norevlookup)
family = rb_str_new2(pbuf); family = rb_str_new2(pbuf);
break; break;
} }
if (!do_not_reverse_lookup) {
if (!norevlookup) {
error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf), error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
NULL, 0, 0); NULL, 0, 0);
if (error) { if (error) {
raise_socket_error("getnameinfo", error); rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error));
} }
addr1 = rb_str_new2(hbuf); addr1 = rb_str_new2(hbuf);
} }
error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf), error = getnameinfo(sockaddr, SA_LEN(sockaddr), hbuf, sizeof(hbuf),
pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV); pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (error) { if (error) {
raise_socket_error("getnameinfo", error); rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error));
} }
addr2 = rb_str_new2(hbuf); addr2 = rb_str_new2(hbuf);
if (norevlookup) { if (do_not_reverse_lookup) {
addr1 = addr2; addr1 = addr2;
} }
port = INT2FIX(atoi(pbuf)); port = INT2FIX(atoi(pbuf));
@ -1086,48 +1042,43 @@ socks_s_close(sock)
#endif #endif
#endif #endif
static VALUE struct hostent_arg {
sock_gethostbyname(host, ipaddr)
VALUE host; VALUE host;
VALUE (*ipaddr) _((struct sockaddr*, size_t)); struct addrinfo* addr;
VALUE (*ipaddr)_((struct sockaddr*, size_t));
};
static VALUE
make_hostent_internal(arg)
struct hostent_arg *arg;
{ {
struct addrinfo *addr; VALUE host = arg->host;
struct addrinfo* addr = arg->addr;
VALUE (*ipaddr)_((struct sockaddr*, size_t)) = arg->ipaddr;
struct addrinfo *ai; struct addrinfo *ai;
struct hostent *h; struct hostent *h;
VALUE ary, names; VALUE ary, names;
char *hostname;
char **pch; char **pch;
const char* hostp;
char hbuf[NI_MAXHOST];
addr = sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME);
ary = rb_ary_new(); ary = rb_ary_new();
if (addr->ai_canonname) { if (addr->ai_canonname) {
hostname = addr->ai_canonname; hostp = addr->ai_canonname;
} }
else { else {
hostname = StringValuePtr(host); hostp = host_str(host, hbuf, sizeof(hbuf));
} }
rb_ary_push(ary, rb_str_new2(hostname)); rb_ary_push(ary, rb_str_new2(hostp));
#if defined(HAVE_GETIPNODEBYNAME)
{
int error;
h = getipnodebyname(hostname, addr->ai_family, AI_ALL, &error); if (addr->ai_canonname && (h = gethostbyname(addr->ai_canonname))) {
}
#elif defined(HAVE_GETHOSTBYNAME2)
h = gethostbyname2(hostname, addr->ai_family);
#else
h = gethostbyname(hostname);
#endif
if (h) {
names = rb_ary_new(); names = rb_ary_new();
if (h->h_aliases != NULL) { if (h->h_aliases != NULL) {
for (pch = h->h_aliases; *pch; pch++) { for (pch = h->h_aliases; *pch; pch++) {
rb_ary_push(names, rb_str_new2(*pch)); rb_ary_push(names, rb_str_new2(*pch));
} }
} }
#if defined(HAVE_GETIPNODEBYNAME)
freehostent(h);
#endif
} }
else { else {
names = rb_ary_new2(0); names = rb_ary_new2(0);
@ -1141,6 +1092,22 @@ sock_gethostbyname(host, ipaddr)
return ary; return ary;
} }
static VALUE
make_hostent(host, addr, ipaddr)
VALUE host;
struct addrinfo* addr;
VALUE (*ipaddr)_((struct sockaddr*, size_t));
{
VALUE ary;
struct hostent_arg arg;
arg.host = host;
arg.addr = addr;
arg.ipaddr = ipaddr;
ary = rb_ensure(make_hostent_internal, (VALUE)&arg,
RUBY_METHOD_FUNC(freeaddrinfo), (VALUE)addr);
}
VALUE VALUE
tcp_sockaddr(addr, len) tcp_sockaddr(addr, len)
struct sockaddr *addr; struct sockaddr *addr;
@ -1154,7 +1121,7 @@ tcp_s_gethostbyname(obj, host)
VALUE obj, host; VALUE obj, host;
{ {
rb_secure(3); rb_secure(3);
return sock_gethostbyname(host, tcp_sockaddr); return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), tcp_sockaddr);
} }
static VALUE static VALUE
@ -1314,7 +1281,7 @@ ip_addr(sock)
if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0)
rb_sys_fail("getsockname(2)"); rb_sys_fail("getsockname(2)");
return ipaddr((struct sockaddr*)&addr, fptr->mode & FMODE_NOREVLOOKUP); return ipaddr((struct sockaddr*)&addr);
} }
static VALUE static VALUE
@ -1329,7 +1296,7 @@ ip_peeraddr(sock)
if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0)
rb_sys_fail("getpeername(2)"); rb_sys_fail("getpeername(2)");
return ipaddr((struct sockaddr*)&addr, fptr->mode & FMODE_NOREVLOOKUP); return ipaddr((struct sockaddr*)&addr);
} }
static VALUE static VALUE
@ -1715,7 +1682,6 @@ unix_sysaccept(sock)
return s_accept(0, fileno(fptr->f), (struct sockaddr*)&from, &fromlen); return s_accept(0, fileno(fptr->f), (struct sockaddr*)&from, &fromlen);
} }
#ifdef HAVE_SYS_UN_H
static VALUE static VALUE
unixaddr(sockaddr) unixaddr(sockaddr)
struct sockaddr_un *sockaddr; struct sockaddr_un *sockaddr;
@ -1723,7 +1689,6 @@ unixaddr(sockaddr)
return rb_assoc_new(rb_str_new2("AF_UNIX"), return rb_assoc_new(rb_str_new2("AF_UNIX"),
rb_str_new2(sockaddr->sun_path)); rb_str_new2(sockaddr->sun_path));
} }
#endif
static VALUE static VALUE
unix_addr(sock) unix_addr(sock)
@ -2045,10 +2010,7 @@ make_addrinfo(res0)
} }
base = rb_ary_new(); base = rb_ary_new();
for (res = res0; res; res = res->ai_next) { for (res = res0; res; res = res->ai_next) {
ary = ipaddr(res->ai_addr, do_not_reverse_lookup); ary = ipaddr(res->ai_addr);
if (res->ai_canonname) {
RARRAY(ary)->ptr[2] = rb_str_new2(res->ai_canonname);
}
rb_ary_push(ary, INT2FIX(res->ai_family)); rb_ary_push(ary, INT2FIX(res->ai_family));
rb_ary_push(ary, INT2FIX(res->ai_socktype)); rb_ary_push(ary, INT2FIX(res->ai_socktype));
rb_ary_push(ary, INT2FIX(res->ai_protocol)); rb_ary_push(ary, INT2FIX(res->ai_protocol));
@ -2070,7 +2032,7 @@ sock_s_gethostbyname(obj, host)
VALUE obj, host; VALUE obj, host;
{ {
rb_secure(3); rb_secure(3);
return sock_gethostbyname(host, sock_sockaddr); return make_hostent(host, sock_addrinfo(host, Qnil, SOCK_STREAM, AI_CANONNAME), sock_sockaddr);
} }
static VALUE static VALUE
@ -2219,7 +2181,7 @@ sock_s_getaddrinfo(argc, argv)
} }
error = getaddrinfo(hptr, pptr, &hints, &res); error = getaddrinfo(hptr, pptr, &hints, &res);
if (error) { if (error) {
raise_socket_error("getaddrinfo", error); rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error));
} }
ret = make_addrinfo(res); ret = make_addrinfo(res);
@ -2356,11 +2318,11 @@ sock_s_getnameinfo(argc, argv)
error_exit_addr: error_exit_addr:
if (res) freeaddrinfo(res); if (res) freeaddrinfo(res);
raise_socket_error("getaddrinfo", error); rb_raise(rb_eSocket, "getaddrinfo: %s", gai_strerror(error));
error_exit_name: error_exit_name:
if (res) freeaddrinfo(res); if (res) freeaddrinfo(res);
raise_socket_error("getnameinfo", error); rb_raise(rb_eSocket, "getnameinfo: %s", gai_strerror(error));
} }
static VALUE static VALUE
@ -2460,8 +2422,6 @@ Init_socket()
rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0); rb_define_method(rb_cBasicSocket, "getpeername", bsock_getpeername, 0);
rb_define_method(rb_cBasicSocket, "send", bsock_send, -1); rb_define_method(rb_cBasicSocket, "send", bsock_send, -1);
rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1); rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket); rb_cIPSocket = rb_define_class("IPSocket", rb_cBasicSocket);
rb_define_global_const("IPsocket", rb_cIPSocket); rb_define_global_const("IPsocket", rb_cIPSocket);

View File

@ -561,186 +561,156 @@ The variable ruby-indent-level controls the amount of indentation.
(defun ruby-indent-size (pos nest) (defun ruby-indent-size (pos nest)
(+ pos (* (or nest 1) ruby-indent-level))) (+ pos (* (or nest 1) ruby-indent-level)))
;;; maybe obsolete
(defconst ruby-assign-re "\\s *\\(&&\\|||\\|<<\\|>>\\|[-+*/%&|^]\\)?=\\s *")
;;; maybe obsolete
(defun ruby-beginning-of-arg (start end)
(save-restriction
(narrow-to-region start (1+ end))
(goto-char start)
(let ((beg t) arg)
(while
(progn
(skip-chars-forward " \t\n")
(and (not (eobp))
(= (ruby-forward-sexp) 0)))
(skip-syntax-forward " ")
(cond ((looking-at ",")
(forward-char)
(setq arg start beg t))
((ruby-expr-beg) t)
((looking-at "=>\\s *")
(goto-char (match-end 0))
(setq arg nil beg nil))
((looking-at ruby-assign-re)
(goto-char (match-end 0))
(if beg (setq beg nil arg (point))))
((looking-at ruby-operator-re)
(goto-char (match-end 0))
(echo "foo %s %s" arg beg)
(if beg (setq beg nil arg (match-end 0))))
((not (eq (char-syntax (char-after)) ?\())
(setq start (point)))))
(goto-char (or arg start)))))
(defun ruby-calculate-indent (&optional parse-start) (defun ruby-calculate-indent (&optional parse-start)
(save-excursion (save-excursion
(beginning-of-line) (beginning-of-line)
(let ((indent-point (point)) (let ((indent-point (point))
(case-fold-search nil) (case-fold-search nil)
state bol eol begin state bol eol begin op-end
(paren (progn (skip-syntax-forward " ") (paren (progn (skip-syntax-forward " ")
(and (char-after) (matching-paren (char-after))))) (and (char-after) (matching-paren (char-after)))))
(indent 0)) (indent 0))
(if parse-start (if parse-start
(goto-char parse-start) (goto-char parse-start)
(ruby-beginning-of-indent) (ruby-beginning-of-indent)
(setq parse-start (point))) (setq parse-start (point)))
(back-to-indentation) (back-to-indentation)
(setq indent (current-column)) (setq indent (current-column))
(setq state (ruby-parse-region parse-start indent-point)) (setq state (ruby-parse-region parse-start indent-point))
(cond (cond
((nth 0 state) ; within string ((nth 0 state) ; within string
(setq indent nil)) ; do nothing (setq indent nil)) ; do nothing
((car (nth 1 state)) ; in paren ((car (nth 1 state)) ; in paren
(goto-char (setq begin (cdr (nth 1 state)))) (goto-char (setq begin (cdr (nth 1 state))))
(let ((deep (ruby-deep-indent-paren-p (car (nth 1 state))))) (let ((deep (ruby-deep-indent-paren-p (car (nth 1 state)))))
(if deep (if deep
(cond ((and (eq deep t) (eq (car (nth 1 state)) paren)) (cond ((and (eq deep t) (eq (car (nth 1 state)) paren))
(skip-syntax-backward " ") (skip-syntax-backward " ")
(setq indent (1- (current-column)))) (setq indent (1- (current-column))))
((let ((s (ruby-parse-region (point) indent-point))) ((let ((s (ruby-parse-region (point) indent-point)))
(and (nth 2 s) (> (nth 2 s) 0) (and (nth 2 s) (> (nth 2 s) 0)
(or (goto-char (cdr (nth 1 s))) t))) (or (goto-char (cdr (nth 1 s))) t)))
(forward-word -1) (forward-word -1)
(setq indent (ruby-indent-size (current-column) (nth 2 state)))) (setq indent (ruby-indent-size (current-column) (nth 2 state))))
(t (t
(setq indent (current-column)) (setq indent (current-column))
(cond ((eq deep 'space)) (cond ((eq deep 'space))
(paren (setq indent (1- indent))) (paren (setq indent (1- indent)))
(t (setq indent (ruby-indent-size (1- indent) 1)))))) (t (setq indent (ruby-indent-size (1- indent) 1))))))
(if (nth 3 state) (goto-char (nth 3 state))
(goto-char parse-start) (back-to-indentation))
(setq indent (ruby-indent-size (current-column) (nth 2 state))))))
((and (nth 2 state) (> (nth 2 state) 0)) ; in nest
(if (null (cdr (nth 1 state)))
(error "invalid nest"))
(goto-char (cdr (nth 1 state)))
(forward-word -1) ; skip back a keyword
(setq begin (point))
(cond
((looking-at "do\\>[^_]") ; iter block is a special case
(if (nth 3 state) (goto-char (nth 3 state)) (if (nth 3 state) (goto-char (nth 3 state))
(goto-char parse-start) (back-to-indentation)) (goto-char parse-start) (back-to-indentation))
(setq indent (ruby-indent-size (current-column) (nth 2 state)))) (setq indent (ruby-indent-size (current-column) (nth 2 state))))))
(t ((and (nth 2 state) (> (nth 2 state) 0)) ; in nest
(setq indent (+ (current-column) ruby-indent-level))))) (if (null (cdr (nth 1 state)))
(error "invalid nest"))
((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest (goto-char (cdr (nth 1 state)))
(setq indent (ruby-indent-size (current-column) (nth 2 state))))) (forward-word -1) ; skip back a keyword
(when indent (setq begin (point))
(goto-char indent-point) (cond
(end-of-line) ((looking-at "do\\>[^_]") ; iter block is a special case
(setq eol (point)) (if (nth 3 state) (goto-char (nth 3 state))
(beginning-of-line) (goto-char parse-start) (back-to-indentation))
(cond (setq indent (ruby-indent-size (current-column) (nth 2 state))))
((and (not (ruby-deep-indent-paren-p paren)) (t
(re-search-forward ruby-negative eol t)) (setq indent (+ (current-column) ruby-indent-level)))))
(and (not (eq ?_ (char-after (match-end 0))))
(setq indent (- indent ruby-indent-level)))) ((and (nth 2 state) (< (nth 2 state) 0)) ; in negative nest
;;operator terminated lines (setq indent (ruby-indent-size (current-column) (nth 2 state)))))
((and (when indent
(save-excursion (goto-char indent-point)
(beginning-of-line) (end-of-line)
(not (bobp))) (setq eol (point))
(or (ruby-deep-indent-paren-p t) (beginning-of-line)
(null (car (nth 1 state))))) (cond
;; goto beginning of non-empty no-comment line ((and (not (ruby-deep-indent-paren-p paren))
(let (end done) (re-search-forward ruby-negative eol t))
(while (not done) (and (not (eq ?_ (char-after (match-end 0))))
(skip-chars-backward " \t\n") (setq indent (- indent ruby-indent-level))))
(setq end (point)) ((and
(beginning-of-line) (save-excursion
(if (re-search-forward "^\\s *#" end t) (beginning-of-line)
(beginning-of-line) (not (bobp)))
(setq done t)))) (or (ruby-deep-indent-paren-p t)
(setq bol (point)) (null (car (nth 1 state)))))
(end-of-line) ;; goto beginning of non-empty no-comment line
(skip-chars-backward " \t") (let (end done)
(let (end (pos (point))) (while (not done)
(skip-chars-backward " \t\n")
(setq end (point))
(beginning-of-line) (beginning-of-line)
(while (and (re-search-forward "#" pos t) (if (re-search-forward "^\\s *#" end t)
(setq end (1- (point))) (beginning-of-line)
(ruby-special-char-p end)) (setq done t))))
(setq end nil)) (setq bol (point))
(goto-char (or end pos)) (end-of-line)
(skip-chars-backward " \t") ;; skip the comment at the end
(setq state (ruby-parse-region parse-start (point))) (skip-chars-backward " \t")
(setq begin (or (nth 0 state) (cdr (nth 1 state)))) (let (end (pos (point)))
(goto-char pos)) (beginning-of-line)
(or (bobp) (forward-char -1)) (while (and (re-search-forward "#" pos t)
(and (setq end (1- (point)))
(or (and (looking-at ruby-symbol-re) (or (ruby-special-char-p end)
(skip-chars-backward ruby-symbol-chars) (and (setq state (ruby-parse-region parse-start end))
(looking-at ruby-block-hanging-re) (nth 0 state))))
(not (eq (point) (nth 3 state))) (setq end nil))
(save-excursion (goto-char (or end pos))
(goto-char (match-end 0)) (skip-chars-backward " \t")
(not (looking-at "[a-z_]")))) (setq begin (if (nth 0 state) pos (cdr (nth 1 state))))
(and (looking-at ruby-operator-re) (setq state (ruby-parse-region parse-start (point))))
(not (ruby-special-char-p)) (or (bobp) (forward-char -1))
(let ((c (char-after (point)))) (and
(and (or (and (looking-at ruby-symbol-re)
(or (not (eq ?, c)) (skip-chars-backward ruby-symbol-chars)
(null begin) (looking-at ruby-block-hanging-re)
(save-excursion (not (eq (point) (nth 3 state)))
(goto-char begin) (save-excursion
(skip-chars-forward " \t") (goto-char (match-end 0))
(not (or (eolp) (looking-at "#") (not (looking-at "[a-z_]"))))
(and (eq (car (nth 1 state)) ?{) (and (looking-at ruby-operator-re)
(looking-at "|")))))) (not (ruby-special-char-p))
(or (not (eq ?/ c)) ;; operator at the end of line
(null (nth 0 (ruby-parse-region (or begin parse-start) (point))))) (let ((c (char-after (point))))
(or (not (eq ?| (char-after (point)))) (and
(save-excursion ;; (or (null begin)
(or (eolp) (forward-char -1)) ;; (save-excursion
(cond ;; (goto-char begin)
((search-backward "|" nil t) ;; (skip-chars-forward " \t")
(skip-chars-backward " \t\n") ;; (not (or (eolp) (looking-at "#")
(and (not (eolp)) ;; (and (eq (car (nth 1 state)) ?{)
(progn ;; (looking-at "|"))))))
(forward-char -1) (or (not (eq ?/ c))
(not (looking-at "{"))) (null (nth 0 (ruby-parse-region (or begin parse-start) (point)))))
(progn (or (not (eq ?| (char-after (point))))
(forward-word -1) (save-excursion
(not (looking-at "do\\>[^_]"))))) (or (eolp) (forward-char -1))
(t t)))))))) (cond
(setq indent ((search-backward "|" nil t)
(cond (skip-chars-backward " \t\n")
((and (and (not (eolp))
(not (looking-at ruby-block-hanging-re)) (progn
(eq (ruby-deep-indent-paren-p t) 'space) (forward-char -1)
(not (bobp))) (not (looking-at "{")))
(save-excursion (progn
(widen) (forward-word -1)
(goto-char (or begin parse-start)) (not (looking-at "do\\>[^_]")))))
(skip-syntax-forward " ") (t t))))
;; (ruby-beginning-of-arg (or begin parse-start) (point)) (not (eq ?, c))
(current-column))) (setq op-end t)))))
(t (setq indent
(+ indent ruby-indent-level)))))))) (cond
indent))) ((and
(null op-end)
(not (looking-at ruby-block-hanging-re))
(eq (ruby-deep-indent-paren-p t) 'space)
(not (bobp)))
(save-excursion
(widen)
(goto-char (or begin parse-start))
(skip-syntax-forward " ")
(current-column)))
(t
(+ indent ruby-indent-level))))))))
indent)))
(defun ruby-electric-brace (arg) (defun ruby-electric-brace (arg)
(interactive "P") (interactive "P")