mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/socket/socket.c (bsock_do_not_rev_lookup_set): should not be
allowed when $SAFE > 3. * eval.c (rb_thread_ready): THREAD_TO_KILL threads should not turn into THREAD_RUNNABLE on wakeup. * eval.c (rb_thread_list): THREAD_TO_KILL threads should be in the list. * eval.c (thgroup_list): ditto; by moving gid clearance from rb_thread_cleanup(). * dir.c (fnmatch): "*/bar" (with FNM_PATHNAME flag) does not match "foo/bar". * io.c (read_all): files on /proc filesystem with zero stat size, may have contents. * ext/socket/socket.c (tcp_s_gethostbyname): refactored. * ext/socket/socket.c (sock_s_gethostbyname): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2271 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a42bf2edd0
commit
e748f56a6b
6 changed files with 119 additions and 124 deletions
34
ChangeLog
34
ChangeLog
|
@ -1,13 +1,43 @@
|
|||
Mon Mar 25 13:24:20 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* ext/socket/socket.c (bsock_do_not_rev_lookup_set): should not be
|
||||
allowed when $SAFE > 3.
|
||||
|
||||
* eval.c (rb_thread_ready): THREAD_TO_KILL threads should not turn
|
||||
into THREAD_RUNNABLE on wakeup.
|
||||
|
||||
* eval.c (rb_thread_list): THREAD_TO_KILL threads should be in the
|
||||
list.
|
||||
|
||||
* eval.c (thgroup_list): ditto; by moving gid clearance from
|
||||
rb_thread_cleanup().
|
||||
|
||||
Mon Mar 25 11:06:19 2002 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp>
|
||||
|
||||
* dln.c (dln_argv0): unused unless USE_DLN_A_OUT.
|
||||
|
||||
* regex.c (mbc_startpos_func): should be static.
|
||||
|
||||
Sun Mar 24 12:19:09 2002 Koji Arai <jca02266@nifty.ne.jp>
|
||||
|
||||
* dir.c (fnmatch): "*/bar" (with FNM_PATHNAME flag) does not
|
||||
match "foo/bar".
|
||||
|
||||
Sun Mar 24 00:46:05 2002 WATANABE Hirofumi <eban@ruby-lang.org>
|
||||
|
||||
* util.c (push_element): avoid warning for djgpp.
|
||||
|
||||
Sat Mar 23 01:50:30 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* io.c (read_all): files on /proc filesystem with zero stat size,
|
||||
may have contents.
|
||||
|
||||
Fri Mar 22 18:07:29 2002 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* ext/socket/socket.c (tcp_s_gethostbyname): refactored.
|
||||
|
||||
* ext/socket/socket.c (sock_s_gethostbyname): ditto.
|
||||
|
||||
Fri Mar 22 16:46:54 2002 Minero Aoki <aamine@loveruby.net>
|
||||
|
||||
* ext/extmk.rb.in: replace mkdir with mkpath to compile racc/cparse.
|
||||
|
@ -54,6 +84,10 @@ Fri Mar 22 13:51:11 2002 Akinori MUSHA <knu@iDaemons.org>
|
|||
* ext/bigfloat/.cvsignore, ext/bigfloat/MANIFEST: BigFloat 1.1.8
|
||||
has been imported. Add .cvsignore and MANIFEST.
|
||||
|
||||
Fri Mar 22 04:07:55 2002 Koji Arai <jca02266@nifty.ne.jp>
|
||||
|
||||
* sprintf.c (rb_f_printf): discard meaningless prefix ".." for '%u'.
|
||||
|
||||
Thu Mar 21 01:11:37 2002 Usaku Nakamura <usa@ruby-lang.org>
|
||||
|
||||
* win32/Makefile.sub (config.status): fix install path (prefix).
|
||||
|
|
4
dir.c
4
dir.c
|
@ -178,8 +178,10 @@ fnmatch(pat, string, flags)
|
|||
}
|
||||
else if (ISDIRSEP(c)) {
|
||||
s = find_dirsep(s);
|
||||
if (s)
|
||||
if (s) {
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
|
|
10
eval.c
10
eval.c
|
@ -7527,7 +7527,9 @@ rb_thread_ready(th)
|
|||
rb_thread_t th;
|
||||
{
|
||||
th->wait_for = 0;
|
||||
th->status = THREAD_RUNNABLE;
|
||||
if (th->status != THREAD_TO_KILL) {
|
||||
th->status = THREAD_RUNNABLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -7538,6 +7540,7 @@ rb_thread_remove(th)
|
|||
|
||||
rb_thread_ready(th);
|
||||
th->status = THREAD_KILLED;
|
||||
th->gid = 0;
|
||||
th->prev->next = th->next;
|
||||
th->next->prev = th->prev;
|
||||
}
|
||||
|
@ -7843,7 +7846,6 @@ rb_thread_schedule()
|
|||
}
|
||||
END_FOREACH_FROM(curr, th);
|
||||
next = main_thread;
|
||||
next->gid = 0;
|
||||
rb_thread_ready(next);
|
||||
next->status = THREAD_TO_KILL;
|
||||
rb_thread_save_context(curr_thread);
|
||||
|
@ -8121,6 +8123,7 @@ rb_thread_list()
|
|||
switch (th->status) {
|
||||
case THREAD_RUNNABLE:
|
||||
case THREAD_STOPPED:
|
||||
case THREAD_TO_KILL:
|
||||
rb_ary_push(ary, th->thread);
|
||||
default:
|
||||
break;
|
||||
|
@ -8936,12 +8939,12 @@ rb_thread_inspect(thread)
|
|||
void
|
||||
rb_thread_atfork()
|
||||
{
|
||||
#if 1 /* enable on 1.7 */
|
||||
rb_thread_t th;
|
||||
|
||||
if (rb_thread_alone()) return;
|
||||
FOREACH_THREAD(th) {
|
||||
if (th != curr_thread) {
|
||||
th->gid = 0;
|
||||
th->status = THREAD_KILLED;
|
||||
}
|
||||
}
|
||||
|
@ -8949,7 +8952,6 @@ rb_thread_atfork()
|
|||
main_thread = curr_thread;
|
||||
curr_thread->next = curr_thread;
|
||||
curr_thread->prev = curr_thread;
|
||||
#endif
|
||||
}
|
||||
|
||||
static VALUE rb_cCont;
|
||||
|
|
|
@ -125,7 +125,7 @@ static int lookup_order_table[LOOKUP_ORDERS] = {
|
|||
};
|
||||
|
||||
static int
|
||||
rb_getaddrinfo(nodename, servname, hints, res)
|
||||
ruby_getaddrinfo(nodename, servname, hints, res)
|
||||
char *nodename;
|
||||
char *servname;
|
||||
struct addrinfo *hints;
|
||||
|
@ -155,7 +155,7 @@ rb_getaddrinfo(nodename, servname, hints, res)
|
|||
|
||||
return error;
|
||||
}
|
||||
#define getaddrinfo(node,serv,hints,res) rb_getaddrinfo((node),(serv),(hints),(res))
|
||||
#define getaddrinfo(node,serv,hints,res) ruby_getaddrinfo((node),(serv),(hints),(res))
|
||||
#endif
|
||||
|
||||
#ifdef NT
|
||||
|
@ -495,6 +495,7 @@ bsock_do_not_rev_lookup()
|
|||
static VALUE
|
||||
bsock_do_not_rev_lookup_set(self, val)
|
||||
{
|
||||
rb_secure(4);
|
||||
do_not_reverse_lookup = RTEST(val);
|
||||
return val;
|
||||
}
|
||||
|
@ -539,8 +540,9 @@ mkinetaddr(host, buf, len)
|
|||
}
|
||||
|
||||
static struct addrinfo*
|
||||
ip_addrsetup(host, port)
|
||||
sock_addrinfo(host, port, flags)
|
||||
VALUE host, port;
|
||||
int flags;
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
char *hostp, *portp;
|
||||
|
@ -561,7 +563,7 @@ ip_addrsetup(host, port)
|
|||
|
||||
SafeStringValue(host);
|
||||
name = RSTRING(host)->ptr;
|
||||
if (*name == 0) {
|
||||
if (*name == 0 || (name[0] == '<' && strcmp(name, "<any>") == 0)) {
|
||||
mkinetaddr(INADDR_ANY, hbuf, sizeof(hbuf));
|
||||
}
|
||||
else if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
|
||||
|
@ -589,8 +591,7 @@ ip_addrsetup(host, port)
|
|||
|
||||
MEMZERO(&hints, struct addrinfo, 1);
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_flags = flags;
|
||||
error = getaddrinfo(hostp, portp, &hints, &res);
|
||||
if (error) {
|
||||
if (hostp && hostp[strlen(hostp)-1] == '\n') {
|
||||
|
@ -605,9 +606,9 @@ ip_addrsetup(host, port)
|
|||
static void
|
||||
setipaddr(name, addr)
|
||||
VALUE name;
|
||||
struct sockaddr *addr;
|
||||
struct sockaddr_storage *addr;
|
||||
{
|
||||
struct addrinfo *res = ip_addrsetup(name, Qnil);
|
||||
struct addrinfo *res = sock_addrinfo(name, Qnil, 0);
|
||||
|
||||
/* just take the first one */
|
||||
memcpy(addr, res->ai_addr, res->ai_addrlen);
|
||||
|
@ -822,7 +823,6 @@ load_addr_info(h, serv, type, res)
|
|||
}
|
||||
MEMZERO(&hints, struct addrinfo, 1);
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (type == INET_SERVER) {
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
}
|
||||
|
@ -841,14 +841,16 @@ init_inetsock(sock, remote_host, remote_serv, local_host, local_serv, type)
|
|||
int fd, status;
|
||||
char *syscall;
|
||||
|
||||
load_addr_info(remote_host, remote_serv, type, &res_remote);
|
||||
|
||||
res_remote = sock_addrinfo(remote_host, remote_serv,
|
||||
(type == INET_SERVER) ? AI_PASSIVE : 0);
|
||||
/*
|
||||
* Maybe also accept a local address
|
||||
*/
|
||||
|
||||
if (type != INET_SERVER && (!NIL_P(local_host) || !NIL_P(local_serv)))
|
||||
load_addr_info(local_host, local_serv, type, &res_local);
|
||||
if (type != INET_SERVER && (!NIL_P(local_host) || !NIL_P(local_serv))) {
|
||||
res_local = sock_addrinfo(local_host, local_serv,
|
||||
(type == INET_SERVER) ? AI_PASSIVE : 0);
|
||||
}
|
||||
|
||||
fd = -1;
|
||||
for (res = res_remote; res; res = res->ai_next) {
|
||||
|
@ -969,32 +971,18 @@ socks_s_close(sock)
|
|||
* NOTE: using gethostbyname() against AF_INET6 is a bad idea, as it
|
||||
* does not initialize sin_flowinfo nor sin_scope_id properly.
|
||||
*/
|
||||
static VALUE
|
||||
tcp_s_gethostbyname(obj, host)
|
||||
VALUE obj, host;
|
||||
|
||||
struct hostent*
|
||||
sock_hostbyname(host)
|
||||
VALUE host;
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
struct hostent *h;
|
||||
char **pch;
|
||||
VALUE ary, names;
|
||||
size_t size;
|
||||
|
||||
rb_secure(3);
|
||||
if (rb_obj_is_kind_of(host, rb_cInteger)) {
|
||||
long i = NUM2LONG(host);
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in*)&addr;
|
||||
MEMZERO(sin, struct sockaddr_in, 1);
|
||||
sin->sin_family = AF_INET;
|
||||
SET_SIN_LEN(sin, sizeof(*sin));
|
||||
sin->sin_addr.s_addr = htonl(i);
|
||||
}
|
||||
else {
|
||||
setipaddr(host, &addr);
|
||||
}
|
||||
setipaddr(host, &addr);
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
sin = (struct sockaddr_in*)&addr;
|
||||
|
@ -1004,7 +992,7 @@ tcp_s_gethostbyname(obj, host)
|
|||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *sin6;
|
||||
sin6 = (struct sockaddr_in6*)&addr;
|
||||
|
@ -1014,8 +1002,9 @@ tcp_s_gethostbyname(obj, host)
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
default:
|
||||
h = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (h == NULL) {
|
||||
|
@ -1026,6 +1015,18 @@ tcp_s_gethostbyname(obj, host)
|
|||
rb_raise(rb_eSocket, "host not found");
|
||||
#endif
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
tcp_s_gethostbyname(obj, host)
|
||||
VALUE obj, host;
|
||||
{
|
||||
struct hostent *h = sock_hostbyname(host);
|
||||
VALUE ary, names;
|
||||
char **pch;
|
||||
size_t size;
|
||||
|
||||
ary = rb_ary_new();
|
||||
rb_ary_push(ary, rb_tainted_str_new2(h->h_name));
|
||||
names = rb_ary_new();
|
||||
|
@ -1035,47 +1036,33 @@ tcp_s_gethostbyname(obj, host)
|
|||
}
|
||||
rb_ary_push(ary, INT2NUM(h->h_addrtype));
|
||||
#ifdef h_addr
|
||||
for (pch = h->h_addr_list; *pch; pch++)
|
||||
;
|
||||
pch++;
|
||||
size = (char*)pch - (char*)h->h_addr_list;
|
||||
pch = (char**)alloca(size);
|
||||
memcpy((char*)pch, (char *)h->h_addr_list, size);
|
||||
size = h->h_length;
|
||||
for (; *pch && h; pch++) {
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
for (pch = h->h_addr_list; *pch; pch++) {
|
||||
switch (h->h_length) {
|
||||
case 4: /* AF_INET */ {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
MEMZERO(&sin, struct sockaddr_in, 1);
|
||||
sin.sin_family = AF_INET;
|
||||
SET_SIN_LEN(&sin, sizeof(sin));
|
||||
memcpy((char*)&sin.sin_addr, *pch, size);
|
||||
h = gethostbyaddr((char*)&sin.sin_addr,
|
||||
sizeof(sin.sin_addr),
|
||||
sin.sin_family);
|
||||
memcpy((char*)&sin.sin_addr, *pch, h->h_length);
|
||||
rb_ary_push(ary, mkipaddr((struct sockaddr*)&sin));
|
||||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
case AF_INET6: {
|
||||
case 8: /* AF_INET6 */ {
|
||||
struct sockaddr_in6 sin6;
|
||||
|
||||
MEMZERO(&sin6, struct sockaddr_in6, 1);
|
||||
sin6.sin6_family = AF_INET;
|
||||
sin6.sin6_family = AF_INET6;
|
||||
#ifdef SIN6_LEN
|
||||
sin6.sin6_len = sizeof(sin6);
|
||||
#endif
|
||||
memcpy((char*)&sin6.sin6_addr, *pch, size);
|
||||
h = gethostbyaddr((char*)&sin6.sin6_addr,
|
||||
sizeof(sin6.sin6_addr),
|
||||
sin6.sin6_family);
|
||||
rb_ary_push(ary, mkipaddr((struct sockaddr*)&sin6));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
h = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1282,7 +1269,7 @@ udp_connect(sock, host, port)
|
|||
rb_secure(3);
|
||||
GetOpenFile(sock, fptr);
|
||||
fd = fileno(fptr->f);
|
||||
res0 = ip_addrsetup(host, port);
|
||||
res0 = sock_addrinfo(host, port, 0);
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
if (ruby_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
|
||||
freeaddrinfo(res0);
|
||||
|
@ -1304,7 +1291,7 @@ udp_bind(sock, host, port)
|
|||
|
||||
rb_secure(3);
|
||||
GetOpenFile(sock, fptr);
|
||||
res0 = ip_addrsetup(host, port);
|
||||
res0 = sock_addrinfo(host, port, 0);
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
if (bind(fileno(fptr->f), res->ai_addr, res->ai_addrlen) < 0) {
|
||||
continue;
|
||||
|
@ -1336,7 +1323,7 @@ udp_send(argc, argv, sock)
|
|||
rb_scan_args(argc, argv, "4", &mesg, &flags, &host, &port);
|
||||
|
||||
GetOpenFile(sock, fptr);
|
||||
res0 = ip_addrsetup(host, port);
|
||||
res0 = sock_addrinfo(host, port, 0);
|
||||
f = GetWriteFile(fptr);
|
||||
StringValue(mesg);
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
|
@ -1877,7 +1864,7 @@ sock_gethostname(obj)
|
|||
#endif
|
||||
|
||||
static VALUE
|
||||
mkhostent(h)
|
||||
sock_mkhostent(h)
|
||||
struct hostent *h;
|
||||
{
|
||||
char **pch;
|
||||
|
@ -1931,55 +1918,11 @@ mkaddrinfo(res0)
|
|||
return base;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: using gethostbyname() against AF_INET6 is a bad idea, as it
|
||||
* does not initialize sin_flowinfo nor sin_scope_id properly.
|
||||
*/
|
||||
static VALUE
|
||||
sock_s_gethostbyname(obj, host)
|
||||
VALUE obj, host;
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
struct hostent *h;
|
||||
|
||||
if (rb_obj_is_kind_of(host, rb_cInteger)) {
|
||||
long i = NUM2LONG(host);
|
||||
struct sockaddr_in *sin;
|
||||
sin = (struct sockaddr_in*)&addr;
|
||||
MEMZERO(sin, struct sockaddr_in, 1);
|
||||
sin->sin_family = AF_INET;
|
||||
SET_SIN_LEN(sin, sizeof(*sin));
|
||||
sin->sin_addr.s_addr = htonl(i);
|
||||
}
|
||||
else {
|
||||
setipaddr(host, (struct sockaddr*)&addr);
|
||||
}
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
sin = (struct sockaddr_in*)&addr;
|
||||
h = gethostbyaddr((char*)&sin->sin_addr,
|
||||
sizeof(sin->sin_addr),
|
||||
sin->sin_family);
|
||||
break;
|
||||
}
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *sin6;
|
||||
sin6 = (struct sockaddr_in6*)&addr;
|
||||
h = gethostbyaddr((char*)&sin6->sin6_addr,
|
||||
sizeof(sin6->sin6_addr),
|
||||
sin6->sin6_family);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
h = NULL;
|
||||
}
|
||||
|
||||
return mkhostent(h);
|
||||
return sock_mkhostent(sock_hostbyname(host));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -2004,7 +1947,7 @@ sock_s_gethostbyaddr(argc, argv)
|
|||
#endif
|
||||
h = gethostbyaddr(RSTRING(addr)->ptr, RSTRING(addr)->len, t);
|
||||
|
||||
return mkhostent(h);
|
||||
return sock_mkhostent(h);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -2251,7 +2194,7 @@ static VALUE
|
|||
sock_s_pack_sockaddr_in(self, port, host)
|
||||
VALUE self, port, host;
|
||||
{
|
||||
struct addrinfo *res = ip_addrsetup(host, port);
|
||||
struct addrinfo *res = sock_addrinfo(host, port, 0);
|
||||
VALUE addr = rb_str_new((char*)res->ai_addr, res->ai_addrlen);
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
|
22
io.c
22
io.c
|
@ -626,17 +626,21 @@ read_all(port)
|
|||
#endif
|
||||
)
|
||||
{
|
||||
off_t pos;
|
||||
|
||||
if (st.st_size == 0) {
|
||||
getc(fptr->f); /* force EOF */
|
||||
return rb_str_new(0, 0);
|
||||
int c = getc(fptr->f);
|
||||
|
||||
if (c == EOF) {
|
||||
return rb_str_new(0, 0);
|
||||
}
|
||||
ungetc(c, fptr->f);
|
||||
}
|
||||
else {
|
||||
off_t pos = ftello(fptr->f);
|
||||
if (st.st_size > pos && pos >= 0) {
|
||||
siz = st.st_size - pos + 1;
|
||||
if (siz > LONG_MAX) {
|
||||
rb_raise(rb_eIOError, "file too big for single read");
|
||||
}
|
||||
pos = ftello(fptr->f);
|
||||
if (st.st_size > pos && pos >= 0) {
|
||||
siz = st.st_size - pos + 1;
|
||||
if (siz > LONG_MAX) {
|
||||
rb_raise(rb_eIOError, "file too big for single read");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
sprintf.c
18
sprintf.c
|
@ -438,8 +438,13 @@ rb_f_sprintf(argc, argv)
|
|||
}
|
||||
s = nbuf;
|
||||
if (v < 0) {
|
||||
strcpy(s, "..");
|
||||
s += 2;
|
||||
if (base == 10) {
|
||||
rb_warning("negative number for %%u specifier");
|
||||
}
|
||||
else {
|
||||
strcpy(s, "..");
|
||||
s += 2;
|
||||
}
|
||||
}
|
||||
sprintf(fbuf, "%%l%c", *p);
|
||||
sprintf(s, fbuf, v);
|
||||
|
@ -491,8 +496,13 @@ rb_f_sprintf(argc, argv)
|
|||
remove_sign_bits(++s, base);
|
||||
val = rb_str_new(0, 3+strlen(s));
|
||||
t = RSTRING(val)->ptr;
|
||||
strcpy(t, "..");
|
||||
t += 2;
|
||||
if (base == 10) {
|
||||
rb_warning("negative number for %%u specifier");
|
||||
}
|
||||
else {
|
||||
strcpy(t, "..");
|
||||
t += 2;
|
||||
}
|
||||
switch (base) {
|
||||
case 16:
|
||||
if (s[0] != 'f') strcpy(t++, "f"); break;
|
||||
|
|
Loading…
Reference in a new issue