1 /* -*- buffer-read-only: t -*- 2 * 3 * reentr.c 4 * 5 * Copyright (C) 2002, 2003, 2005, 2006, 2007 by Larry Wall and others 6 * 7 * You may distribute under the terms of either the GNU General Public 8 * License or the Artistic License, as specified in the README file. 9 * 10 * !!!!!!! DO NOT EDIT THIS FILE !!!!!!! 11 * This file is built by regen/reentr.pl from data in regen/reentr.pl. 12 * Any changes made here will be lost! 13 */ 14 15 /* 16 * "Saruman," I said, standing away from him, "only one hand at a time can 17 * wield the One, and you know that well, so do not trouble to say we!" 18 * 19 * [p.260 of _The Lord of the Rings_, II/ii: "The Council of Elrond"] 20 */ 21 22 /* 23 * This file contains a collection of automatically created wrappers 24 * (created by running reentr.pl) for reentrant (thread-safe) versions of 25 * various library calls, such as getpwent_r. The wrapping is done so 26 * that other files like pp_sys.c calling those library functions need not 27 * care about the differences between various platforms' idiosyncrasies 28 * regarding these reentrant interfaces. 29 */ 30 31 #include "EXTERN.h" 32 #define PERL_IN_REENTR_C 33 #include "perl.h" 34 #include "reentr.h" 35 36 void 37 Perl_reentrant_size(pTHX) { 38 PERL_UNUSED_CONTEXT; 39 #ifdef USE_REENTRANT_API 40 #define REENTRANTSMALLSIZE 256 /* Make something up. */ 41 #define REENTRANTUSUALSIZE 4096 /* Make something up. */ 42 #ifdef HAS_ASCTIME_R 43 PL_reentrant_buffer->_asctime_size = REENTRANTSMALLSIZE; 44 #endif /* HAS_ASCTIME_R */ 45 #ifdef HAS_CRYPT_R 46 #endif /* HAS_CRYPT_R */ 47 #ifdef HAS_CTIME_R 48 PL_reentrant_buffer->_ctime_size = REENTRANTSMALLSIZE; 49 #endif /* HAS_CTIME_R */ 50 #ifdef HAS_GETGRNAM_R 51 # if defined(HAS_SYSCONF) && defined(_SC_GETGR_R_SIZE_MAX) && !defined(__GLIBC__) 52 PL_reentrant_buffer->_grent_size = sysconf(_SC_GETGR_R_SIZE_MAX); 53 if (PL_reentrant_buffer->_grent_size == (size_t) -1) 54 PL_reentrant_buffer->_grent_size = REENTRANTUSUALSIZE; 55 # else 56 # if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ) 57 PL_reentrant_buffer->_grent_size = SIABUFSIZ; 58 # else 59 # ifdef __sgi 60 PL_reentrant_buffer->_grent_size = BUFSIZ; 61 # else 62 PL_reentrant_buffer->_grent_size = REENTRANTUSUALSIZE; 63 # endif 64 # endif 65 # endif 66 #endif /* HAS_GETGRNAM_R */ 67 #ifdef HAS_GETHOSTBYNAME_R 68 #if !(GETHOSTBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 69 PL_reentrant_buffer->_hostent_size = REENTRANTUSUALSIZE; 70 #endif 71 #endif /* HAS_GETHOSTBYNAME_R */ 72 #ifdef HAS_GETLOGIN_R 73 PL_reentrant_buffer->_getlogin_size = REENTRANTSMALLSIZE; 74 #endif /* HAS_GETLOGIN_R */ 75 #ifdef HAS_GETNETBYNAME_R 76 #if !(GETNETBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 77 PL_reentrant_buffer->_netent_size = REENTRANTUSUALSIZE; 78 #endif 79 #endif /* HAS_GETNETBYNAME_R */ 80 #ifdef HAS_GETPROTOBYNAME_R 81 #if !(GETPROTOBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 82 PL_reentrant_buffer->_protoent_size = REENTRANTUSUALSIZE; 83 #endif 84 #endif /* HAS_GETPROTOBYNAME_R */ 85 #ifdef HAS_GETPWNAM_R 86 # if defined(HAS_SYSCONF) && defined(_SC_GETPW_R_SIZE_MAX) && !defined(__GLIBC__) 87 PL_reentrant_buffer->_pwent_size = sysconf(_SC_GETPW_R_SIZE_MAX); 88 if (PL_reentrant_buffer->_pwent_size == (size_t) -1) 89 PL_reentrant_buffer->_pwent_size = REENTRANTUSUALSIZE; 90 # else 91 # if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ) 92 PL_reentrant_buffer->_pwent_size = SIABUFSIZ; 93 # else 94 # ifdef __sgi 95 PL_reentrant_buffer->_pwent_size = BUFSIZ; 96 # else 97 PL_reentrant_buffer->_pwent_size = REENTRANTUSUALSIZE; 98 # endif 99 # endif 100 # endif 101 #endif /* HAS_GETPWNAM_R */ 102 #ifdef HAS_GETSERVBYNAME_R 103 #if !(GETSERVBYNAME_R_PROTO == REENTRANT_PROTO_I_CCSD) 104 PL_reentrant_buffer->_servent_size = REENTRANTUSUALSIZE; 105 #endif 106 #endif /* HAS_GETSERVBYNAME_R */ 107 #ifdef HAS_GETSPNAM_R 108 # if defined(HAS_SYSCONF) && defined(_SC_GETPW_R_SIZE_MAX) && !defined(__GLIBC__) 109 PL_reentrant_buffer->_spent_size = sysconf(_SC_GETPW_R_SIZE_MAX); 110 if (PL_reentrant_buffer->_spent_size == (size_t) -1) 111 PL_reentrant_buffer->_spent_size = REENTRANTUSUALSIZE; 112 # else 113 # if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ) 114 PL_reentrant_buffer->_spent_size = SIABUFSIZ; 115 # else 116 # ifdef __sgi 117 PL_reentrant_buffer->_spent_size = BUFSIZ; 118 # else 119 PL_reentrant_buffer->_spent_size = REENTRANTUSUALSIZE; 120 # endif 121 # endif 122 # endif 123 #endif /* HAS_GETSPNAM_R */ 124 #ifdef HAS_READDIR_R 125 /* This is the size Solaris recommends. 126 * (though we go static, should use pathconf() instead) */ 127 PL_reentrant_buffer->_readdir_size = sizeof(struct dirent) + MAXPATHLEN + 1; 128 #endif /* HAS_READDIR_R */ 129 #ifdef HAS_READDIR64_R 130 /* This is the size Solaris recommends. 131 * (though we go static, should use pathconf() instead) */ 132 PL_reentrant_buffer->_readdir64_size = sizeof(struct dirent64) + MAXPATHLEN + 1; 133 #endif /* HAS_READDIR64_R */ 134 #ifdef HAS_SETLOCALE_R 135 PL_reentrant_buffer->_setlocale_size = REENTRANTSMALLSIZE; 136 #endif /* HAS_SETLOCALE_R */ 137 #ifdef HAS_STRERROR_R 138 PL_reentrant_buffer->_strerror_size = REENTRANTSMALLSIZE; 139 #endif /* HAS_STRERROR_R */ 140 #ifdef HAS_TTYNAME_R 141 PL_reentrant_buffer->_ttyname_size = REENTRANTSMALLSIZE; 142 #endif /* HAS_TTYNAME_R */ 143 144 #endif /* USE_REENTRANT_API */ 145 } 146 147 void 148 Perl_reentrant_init(pTHX) { 149 PERL_UNUSED_CONTEXT; 150 #ifdef USE_REENTRANT_API 151 Newx(PL_reentrant_buffer, 1, REENTR); 152 Perl_reentrant_size(aTHX); 153 #ifdef HAS_ASCTIME_R 154 Newx(PL_reentrant_buffer->_asctime_buffer, PL_reentrant_buffer->_asctime_size, char); 155 #endif /* HAS_ASCTIME_R */ 156 #ifdef HAS_CRYPT_R 157 #if CRYPT_R_PROTO != REENTRANT_PROTO_B_CCD 158 PL_reentrant_buffer->_crypt_struct_buffer = 0; 159 #endif 160 #endif /* HAS_CRYPT_R */ 161 #ifdef HAS_CTIME_R 162 Newx(PL_reentrant_buffer->_ctime_buffer, PL_reentrant_buffer->_ctime_size, char); 163 #endif /* HAS_CTIME_R */ 164 #ifdef HAS_GETGRNAM_R 165 # ifdef USE_GRENT_FPTR 166 PL_reentrant_buffer->_grent_fptr = NULL; 167 # endif 168 Newx(PL_reentrant_buffer->_grent_buffer, PL_reentrant_buffer->_grent_size, char); 169 #endif /* HAS_GETGRNAM_R */ 170 #ifdef HAS_GETHOSTBYNAME_R 171 #if !(GETHOSTBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 172 Newx(PL_reentrant_buffer->_hostent_buffer, PL_reentrant_buffer->_hostent_size, char); 173 #endif 174 #endif /* HAS_GETHOSTBYNAME_R */ 175 #ifdef HAS_GETLOGIN_R 176 Newx(PL_reentrant_buffer->_getlogin_buffer, PL_reentrant_buffer->_getlogin_size, char); 177 #endif /* HAS_GETLOGIN_R */ 178 #ifdef HAS_GETNETBYNAME_R 179 #if !(GETNETBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 180 Newx(PL_reentrant_buffer->_netent_buffer, PL_reentrant_buffer->_netent_size, char); 181 #endif 182 #endif /* HAS_GETNETBYNAME_R */ 183 #ifdef HAS_GETPROTOBYNAME_R 184 #if !(GETPROTOBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 185 Newx(PL_reentrant_buffer->_protoent_buffer, PL_reentrant_buffer->_protoent_size, char); 186 #endif 187 #endif /* HAS_GETPROTOBYNAME_R */ 188 #ifdef HAS_GETPWNAM_R 189 # ifdef USE_PWENT_FPTR 190 PL_reentrant_buffer->_pwent_fptr = NULL; 191 # endif 192 Newx(PL_reentrant_buffer->_pwent_buffer, PL_reentrant_buffer->_pwent_size, char); 193 #endif /* HAS_GETPWNAM_R */ 194 #ifdef HAS_GETSERVBYNAME_R 195 #if !(GETSERVBYNAME_R_PROTO == REENTRANT_PROTO_I_CCSD) 196 Newx(PL_reentrant_buffer->_servent_buffer, PL_reentrant_buffer->_servent_size, char); 197 #endif 198 #endif /* HAS_GETSERVBYNAME_R */ 199 #ifdef HAS_GETSPNAM_R 200 # ifdef USE_SPENT_FPTR 201 PL_reentrant_buffer->_spent_fptr = NULL; 202 # endif 203 Newx(PL_reentrant_buffer->_spent_buffer, PL_reentrant_buffer->_spent_size, char); 204 #endif /* HAS_GETSPNAM_R */ 205 #ifdef HAS_READDIR_R 206 PL_reentrant_buffer->_readdir_struct = (struct dirent*)safemalloc(PL_reentrant_buffer->_readdir_size); 207 #endif /* HAS_READDIR_R */ 208 #ifdef HAS_READDIR64_R 209 PL_reentrant_buffer->_readdir64_struct = (struct dirent64*)safemalloc(PL_reentrant_buffer->_readdir64_size); 210 #endif /* HAS_READDIR64_R */ 211 #ifdef HAS_SETLOCALE_R 212 Newx(PL_reentrant_buffer->_setlocale_buffer, PL_reentrant_buffer->_setlocale_size, char); 213 #endif /* HAS_SETLOCALE_R */ 214 #ifdef HAS_STRERROR_R 215 Newx(PL_reentrant_buffer->_strerror_buffer, PL_reentrant_buffer->_strerror_size, char); 216 #endif /* HAS_STRERROR_R */ 217 #ifdef HAS_TTYNAME_R 218 Newx(PL_reentrant_buffer->_ttyname_buffer, PL_reentrant_buffer->_ttyname_size, char); 219 #endif /* HAS_TTYNAME_R */ 220 221 #endif /* USE_REENTRANT_API */ 222 } 223 224 void 225 Perl_reentrant_free(pTHX) { 226 PERL_UNUSED_CONTEXT; 227 #ifdef USE_REENTRANT_API 228 #ifdef HAS_ASCTIME_R 229 Safefree(PL_reentrant_buffer->_asctime_buffer); 230 #endif /* HAS_ASCTIME_R */ 231 #ifdef HAS_CRYPT_R 232 #if CRYPT_R_PROTO != REENTRANT_PROTO_B_CCD 233 Safefree(PL_reentrant_buffer->_crypt_struct_buffer); 234 #endif 235 #endif /* HAS_CRYPT_R */ 236 #ifdef HAS_CTIME_R 237 Safefree(PL_reentrant_buffer->_ctime_buffer); 238 #endif /* HAS_CTIME_R */ 239 #ifdef HAS_GETGRNAM_R 240 Safefree(PL_reentrant_buffer->_grent_buffer); 241 #endif /* HAS_GETGRNAM_R */ 242 #ifdef HAS_GETHOSTBYNAME_R 243 #if !(GETHOSTBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 244 Safefree(PL_reentrant_buffer->_hostent_buffer); 245 #endif 246 #endif /* HAS_GETHOSTBYNAME_R */ 247 #ifdef HAS_GETLOGIN_R 248 Safefree(PL_reentrant_buffer->_getlogin_buffer); 249 #endif /* HAS_GETLOGIN_R */ 250 #ifdef HAS_GETNETBYNAME_R 251 #if !(GETNETBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 252 Safefree(PL_reentrant_buffer->_netent_buffer); 253 #endif 254 #endif /* HAS_GETNETBYNAME_R */ 255 #ifdef HAS_GETPROTOBYNAME_R 256 #if !(GETPROTOBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 257 Safefree(PL_reentrant_buffer->_protoent_buffer); 258 #endif 259 #endif /* HAS_GETPROTOBYNAME_R */ 260 #ifdef HAS_GETPWNAM_R 261 Safefree(PL_reentrant_buffer->_pwent_buffer); 262 #endif /* HAS_GETPWNAM_R */ 263 #ifdef HAS_GETSERVBYNAME_R 264 #if !(GETSERVBYNAME_R_PROTO == REENTRANT_PROTO_I_CCSD) 265 Safefree(PL_reentrant_buffer->_servent_buffer); 266 #endif 267 #endif /* HAS_GETSERVBYNAME_R */ 268 #ifdef HAS_GETSPNAM_R 269 Safefree(PL_reentrant_buffer->_spent_buffer); 270 #endif /* HAS_GETSPNAM_R */ 271 #ifdef HAS_READDIR_R 272 Safefree(PL_reentrant_buffer->_readdir_struct); 273 #endif /* HAS_READDIR_R */ 274 #ifdef HAS_READDIR64_R 275 Safefree(PL_reentrant_buffer->_readdir64_struct); 276 #endif /* HAS_READDIR64_R */ 277 #ifdef HAS_SETLOCALE_R 278 Safefree(PL_reentrant_buffer->_setlocale_buffer); 279 #endif /* HAS_SETLOCALE_R */ 280 #ifdef HAS_STRERROR_R 281 Safefree(PL_reentrant_buffer->_strerror_buffer); 282 #endif /* HAS_STRERROR_R */ 283 #ifdef HAS_TTYNAME_R 284 Safefree(PL_reentrant_buffer->_ttyname_buffer); 285 #endif /* HAS_TTYNAME_R */ 286 287 Safefree(PL_reentrant_buffer); 288 #endif /* USE_REENTRANT_API */ 289 } 290 291 void* 292 Perl_reentrant_retry(const char *f, ...) 293 { 294 void *retptr = NULL; 295 va_list ap; 296 #ifdef USE_REENTRANT_API 297 dTHX; 298 /* Easier to special case this here than in embed.pl. (Look at what it 299 generates for proto.h) */ 300 PERL_ARGS_ASSERT_REENTRANT_RETRY; 301 #endif 302 va_start(ap, f); 303 { 304 #ifdef USE_REENTRANT_API 305 # if defined(USE_HOSTENT_BUFFER) || defined(USE_GRENT_BUFFER) || defined(USE_NETENT_BUFFER) || defined(USE_PWENT_BUFFER) || defined(USE_PROTOENT_BUFFER) || defined(USE_SERVENT_BUFFER) 306 void *p0; 307 # endif 308 # if defined(USE_SERVENT_BUFFER) 309 void *p1; 310 # endif 311 # if defined(USE_HOSTENT_BUFFER) 312 size_t asize; 313 # endif 314 # if defined(USE_HOSTENT_BUFFER) || defined(USE_NETENT_BUFFER) || defined(USE_PROTOENT_BUFFER) || defined(USE_SERVENT_BUFFER) 315 int anint; 316 # endif 317 318 switch (PL_op->op_type) { 319 #ifdef USE_HOSTENT_BUFFER 320 case OP_GHBYADDR: 321 case OP_GHBYNAME: 322 case OP_GHOSTENT: 323 { 324 #ifdef PERL_REENTRANT_MAXSIZE 325 if (PL_reentrant_buffer->_hostent_size <= 326 PERL_REENTRANT_MAXSIZE / 2) 327 #endif 328 { 329 PL_reentrant_buffer->_hostent_size *= 2; 330 Renew(PL_reentrant_buffer->_hostent_buffer, 331 PL_reentrant_buffer->_hostent_size, char); 332 switch (PL_op->op_type) { 333 case OP_GHBYADDR: 334 p0 = va_arg(ap, void *); 335 asize = va_arg(ap, size_t); 336 anint = va_arg(ap, int); 337 retptr = gethostbyaddr(p0, asize, anint); break; 338 case OP_GHBYNAME: 339 p0 = va_arg(ap, void *); 340 retptr = gethostbyname((char *)p0); break; 341 case OP_GHOSTENT: 342 retptr = gethostent(); break; 343 default: 344 SETERRNO(ERANGE, LIB_INVARG); 345 break; 346 } 347 } 348 } 349 break; 350 #endif 351 #ifdef USE_GRENT_BUFFER 352 case OP_GGRNAM: 353 case OP_GGRGID: 354 case OP_GGRENT: 355 { 356 #ifdef PERL_REENTRANT_MAXSIZE 357 if (PL_reentrant_buffer->_grent_size <= 358 PERL_REENTRANT_MAXSIZE / 2) 359 #endif 360 { 361 Gid_t gid; 362 PL_reentrant_buffer->_grent_size *= 2; 363 Renew(PL_reentrant_buffer->_grent_buffer, 364 PL_reentrant_buffer->_grent_size, char); 365 switch (PL_op->op_type) { 366 case OP_GGRNAM: 367 p0 = va_arg(ap, void *); 368 retptr = getgrnam((char *)p0); break; 369 case OP_GGRGID: 370 #if Gid_t_size < INTSIZE 371 gid = (Gid_t)va_arg(ap, int); 372 #else 373 gid = va_arg(ap, Gid_t); 374 #endif 375 retptr = getgrgid(gid); break; 376 case OP_GGRENT: 377 retptr = getgrent(); break; 378 default: 379 SETERRNO(ERANGE, LIB_INVARG); 380 break; 381 } 382 } 383 } 384 break; 385 #endif 386 #ifdef USE_NETENT_BUFFER 387 case OP_GNBYADDR: 388 case OP_GNBYNAME: 389 case OP_GNETENT: 390 { 391 #ifdef PERL_REENTRANT_MAXSIZE 392 if (PL_reentrant_buffer->_netent_size <= 393 PERL_REENTRANT_MAXSIZE / 2) 394 #endif 395 { 396 Netdb_net_t net; 397 PL_reentrant_buffer->_netent_size *= 2; 398 Renew(PL_reentrant_buffer->_netent_buffer, 399 PL_reentrant_buffer->_netent_size, char); 400 switch (PL_op->op_type) { 401 case OP_GNBYADDR: 402 net = va_arg(ap, Netdb_net_t); 403 anint = va_arg(ap, int); 404 retptr = getnetbyaddr(net, anint); break; 405 case OP_GNBYNAME: 406 p0 = va_arg(ap, void *); 407 retptr = getnetbyname((char *)p0); break; 408 case OP_GNETENT: 409 retptr = getnetent(); break; 410 default: 411 SETERRNO(ERANGE, LIB_INVARG); 412 break; 413 } 414 } 415 } 416 break; 417 #endif 418 #ifdef USE_PWENT_BUFFER 419 case OP_GPWNAM: 420 case OP_GPWUID: 421 case OP_GPWENT: 422 { 423 #ifdef PERL_REENTRANT_MAXSIZE 424 if (PL_reentrant_buffer->_pwent_size <= 425 PERL_REENTRANT_MAXSIZE / 2) 426 #endif 427 { 428 Uid_t uid; 429 PL_reentrant_buffer->_pwent_size *= 2; 430 Renew(PL_reentrant_buffer->_pwent_buffer, 431 PL_reentrant_buffer->_pwent_size, char); 432 switch (PL_op->op_type) { 433 case OP_GPWNAM: 434 p0 = va_arg(ap, void *); 435 retptr = getpwnam((char *)p0); break; 436 case OP_GPWUID: 437 #if Uid_t_size < INTSIZE 438 uid = (Uid_t)va_arg(ap, int); 439 #else 440 uid = va_arg(ap, Uid_t); 441 #endif 442 retptr = getpwuid(uid); break; 443 #if defined(HAS_GETPWENT) || defined(HAS_GETPWENT_R) 444 case OP_GPWENT: 445 retptr = getpwent(); break; 446 #endif 447 default: 448 SETERRNO(ERANGE, LIB_INVARG); 449 break; 450 } 451 } 452 } 453 break; 454 #endif 455 #ifdef USE_PROTOENT_BUFFER 456 case OP_GPBYNAME: 457 case OP_GPBYNUMBER: 458 case OP_GPROTOENT: 459 { 460 #ifdef PERL_REENTRANT_MAXSIZE 461 if (PL_reentrant_buffer->_protoent_size <= 462 PERL_REENTRANT_MAXSIZE / 2) 463 #endif 464 { 465 PL_reentrant_buffer->_protoent_size *= 2; 466 Renew(PL_reentrant_buffer->_protoent_buffer, 467 PL_reentrant_buffer->_protoent_size, char); 468 switch (PL_op->op_type) { 469 case OP_GPBYNAME: 470 p0 = va_arg(ap, void *); 471 retptr = getprotobyname((char *)p0); break; 472 case OP_GPBYNUMBER: 473 anint = va_arg(ap, int); 474 retptr = getprotobynumber(anint); break; 475 case OP_GPROTOENT: 476 retptr = getprotoent(); break; 477 default: 478 SETERRNO(ERANGE, LIB_INVARG); 479 break; 480 } 481 } 482 } 483 break; 484 #endif 485 #ifdef USE_SERVENT_BUFFER 486 case OP_GSBYNAME: 487 case OP_GSBYPORT: 488 case OP_GSERVENT: 489 { 490 #ifdef PERL_REENTRANT_MAXSIZE 491 if (PL_reentrant_buffer->_servent_size <= 492 PERL_REENTRANT_MAXSIZE / 2) 493 #endif 494 { 495 PL_reentrant_buffer->_servent_size *= 2; 496 Renew(PL_reentrant_buffer->_servent_buffer, 497 PL_reentrant_buffer->_servent_size, char); 498 switch (PL_op->op_type) { 499 case OP_GSBYNAME: 500 p0 = va_arg(ap, void *); 501 p1 = va_arg(ap, void *); 502 retptr = getservbyname((char *)p0, (char *)p1); break; 503 case OP_GSBYPORT: 504 anint = va_arg(ap, int); 505 p0 = va_arg(ap, void *); 506 retptr = getservbyport(anint, (char *)p0); break; 507 case OP_GSERVENT: 508 retptr = getservent(); break; 509 default: 510 SETERRNO(ERANGE, LIB_INVARG); 511 break; 512 } 513 } 514 } 515 break; 516 #endif 517 default: 518 /* Not known how to retry, so just fail. */ 519 break; 520 } 521 #else 522 PERL_UNUSED_ARG(f); 523 #endif 524 } 525 va_end(ap); 526 return retptr; 527 } 528 529 /* ex: set ro: */ 530