Annotation of embedaddon/php/ext/readline/readline.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 The PHP Group |
! 6: +----------------------------------------------------------------------+
! 7: | This source file is subject to version 3.01 of the PHP license, |
! 8: | that is bundled with this package in the file LICENSE, and is |
! 9: | available through the world-wide-web at the following url: |
! 10: | http://www.php.net/license/3_01.txt |
! 11: | If you did not receive a copy of the PHP license and are unable to |
! 12: | obtain it through the world-wide-web, please send a note to |
! 13: | license@php.net so we can mail you a copy immediately. |
! 14: +----------------------------------------------------------------------+
! 15: | Author: Thies C. Arntzen <thies@thieso.net> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18:
! 19: /* $Id: readline.c 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: /* {{{ includes & prototypes */
! 22:
! 23: #ifdef HAVE_CONFIG_H
! 24: #include "config.h"
! 25: #endif
! 26:
! 27: #include "php.h"
! 28: #include "php_readline.h"
! 29:
! 30: #if HAVE_LIBREADLINE || HAVE_LIBEDIT
! 31:
! 32: #ifndef HAVE_RL_COMPLETION_MATCHES
! 33: #define rl_completion_matches completion_matches
! 34: #endif
! 35:
! 36: #ifdef HAVE_LIBEDIT
! 37: #include <editline/readline.h>
! 38: #else
! 39: #include <readline/readline.h>
! 40: #include <readline/history.h>
! 41: #endif
! 42:
! 43: PHP_FUNCTION(readline);
! 44: PHP_FUNCTION(readline_add_history);
! 45: PHP_FUNCTION(readline_info);
! 46: PHP_FUNCTION(readline_clear_history);
! 47: #ifndef HAVE_LIBEDIT
! 48: PHP_FUNCTION(readline_list_history);
! 49: #endif
! 50: PHP_FUNCTION(readline_read_history);
! 51: PHP_FUNCTION(readline_write_history);
! 52: PHP_FUNCTION(readline_completion_function);
! 53:
! 54: #if HAVE_RL_CALLBACK_READ_CHAR
! 55: PHP_FUNCTION(readline_callback_handler_install);
! 56: PHP_FUNCTION(readline_callback_read_char);
! 57: PHP_FUNCTION(readline_callback_handler_remove);
! 58: PHP_FUNCTION(readline_redisplay);
! 59: PHP_FUNCTION(readline_on_new_line);
! 60:
! 61: static zval *_prepped_callback = NULL;
! 62:
! 63: #endif
! 64:
! 65: static zval *_readline_completion = NULL;
! 66: static zval _readline_array;
! 67:
! 68: PHP_MINIT_FUNCTION(readline);
! 69: PHP_RSHUTDOWN_FUNCTION(readline);
! 70:
! 71: /* }}} */
! 72:
! 73: /* {{{ arginfo */
! 74: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline, 0, 0, 0)
! 75: ZEND_ARG_INFO(0, prompt)
! 76: ZEND_END_ARG_INFO()
! 77:
! 78: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_info, 0, 0, 0)
! 79: ZEND_ARG_INFO(0, varname)
! 80: ZEND_ARG_INFO(0, newvalue)
! 81: ZEND_END_ARG_INFO()
! 82:
! 83: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_add_history, 0, 0, 1)
! 84: ZEND_ARG_INFO(0, prompt)
! 85: ZEND_END_ARG_INFO()
! 86:
! 87: ZEND_BEGIN_ARG_INFO(arginfo_readline_clear_history, 0)
! 88: ZEND_END_ARG_INFO()
! 89:
! 90: #ifndef HAVE_LIBEDIT
! 91: ZEND_BEGIN_ARG_INFO(arginfo_readline_list_history, 0)
! 92: ZEND_END_ARG_INFO()
! 93: #endif
! 94:
! 95: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_read_history, 0, 0, 0)
! 96: ZEND_ARG_INFO(0, filename)
! 97: ZEND_END_ARG_INFO()
! 98:
! 99: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_write_history, 0, 0, 0)
! 100: ZEND_ARG_INFO(0, filename)
! 101: ZEND_END_ARG_INFO()
! 102:
! 103: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_completion_function, 0, 0, 1)
! 104: ZEND_ARG_INFO(0, funcname)
! 105: ZEND_END_ARG_INFO()
! 106:
! 107: #if HAVE_RL_CALLBACK_READ_CHAR
! 108: ZEND_BEGIN_ARG_INFO_EX(arginfo_readline_callback_handler_install, 0, 0, 2)
! 109: ZEND_ARG_INFO(0, prompt)
! 110: ZEND_ARG_INFO(0, callback)
! 111: ZEND_END_ARG_INFO()
! 112:
! 113: ZEND_BEGIN_ARG_INFO(arginfo_readline_callback_read_char, 0)
! 114: ZEND_END_ARG_INFO()
! 115:
! 116: ZEND_BEGIN_ARG_INFO(arginfo_readline_callback_handler_remove, 0)
! 117: ZEND_END_ARG_INFO()
! 118:
! 119: ZEND_BEGIN_ARG_INFO(arginfo_readline_redisplay, 0)
! 120: ZEND_END_ARG_INFO()
! 121:
! 122: ZEND_BEGIN_ARG_INFO(arginfo_readline_on_new_line, 0)
! 123: ZEND_END_ARG_INFO()
! 124: #endif
! 125: /* }}} */
! 126:
! 127: /* {{{ module stuff */
! 128: static const zend_function_entry php_readline_functions[] = {
! 129: PHP_FE(readline, arginfo_readline)
! 130: PHP_FE(readline_info, arginfo_readline_info)
! 131: PHP_FE(readline_add_history, arginfo_readline_add_history)
! 132: PHP_FE(readline_clear_history, arginfo_readline_clear_history)
! 133: #ifndef HAVE_LIBEDIT
! 134: PHP_FE(readline_list_history, arginfo_readline_list_history)
! 135: #endif
! 136: PHP_FE(readline_read_history, arginfo_readline_read_history)
! 137: PHP_FE(readline_write_history, arginfo_readline_write_history)
! 138: PHP_FE(readline_completion_function,arginfo_readline_completion_function)
! 139: #if HAVE_RL_CALLBACK_READ_CHAR
! 140: PHP_FE(readline_callback_handler_install, arginfo_readline_callback_handler_install)
! 141: PHP_FE(readline_callback_read_char, arginfo_readline_callback_read_char)
! 142: PHP_FE(readline_callback_handler_remove, arginfo_readline_callback_handler_remove)
! 143: PHP_FE(readline_redisplay, arginfo_readline_redisplay)
! 144: PHP_FE(readline_on_new_line, arginfo_readline_on_new_line)
! 145: #endif
! 146: PHP_FE_END
! 147: };
! 148:
! 149: zend_module_entry readline_module_entry = {
! 150: STANDARD_MODULE_HEADER,
! 151: "readline",
! 152: php_readline_functions,
! 153: PHP_MINIT(readline),
! 154: NULL,
! 155: NULL,
! 156: PHP_RSHUTDOWN(readline),
! 157: NULL,
! 158: NO_VERSION_YET,
! 159: STANDARD_MODULE_PROPERTIES
! 160: };
! 161:
! 162: #ifdef COMPILE_DL_READLINE
! 163: ZEND_GET_MODULE(readline)
! 164: #endif
! 165:
! 166: PHP_MINIT_FUNCTION(readline)
! 167: {
! 168: using_history();
! 169: return SUCCESS;
! 170: }
! 171:
! 172: PHP_RSHUTDOWN_FUNCTION(readline)
! 173: {
! 174: if (_readline_completion) {
! 175: zval_dtor(_readline_completion);
! 176: FREE_ZVAL(_readline_completion);
! 177: }
! 178: #if HAVE_RL_CALLBACK_READ_CHAR
! 179: if (_prepped_callback) {
! 180: rl_callback_handler_remove();
! 181: zval_ptr_dtor(&_prepped_callback);
! 182: _prepped_callback = 0;
! 183: }
! 184: #endif
! 185:
! 186: return SUCCESS;
! 187: }
! 188:
! 189: /* }}} */
! 190:
! 191: /* {{{ proto string readline([string prompt])
! 192: Reads a line */
! 193: PHP_FUNCTION(readline)
! 194: {
! 195: char *prompt = NULL;
! 196: int prompt_len;
! 197: char *result;
! 198:
! 199: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &prompt, &prompt_len)) {
! 200: RETURN_FALSE;
! 201: }
! 202:
! 203: result = readline(prompt);
! 204:
! 205: if (! result) {
! 206: RETURN_FALSE;
! 207: } else {
! 208: RETVAL_STRING(result,1);
! 209: free(result);
! 210: }
! 211: }
! 212:
! 213: /* }}} */
! 214:
! 215: #define SAFE_STRING(s) ((s)?(char*)(s):"")
! 216:
! 217: /* {{{ proto mixed readline_info([string varname [, string newvalue]])
! 218: Gets/sets various internal readline variables. */
! 219: PHP_FUNCTION(readline_info)
! 220: {
! 221: char *what = NULL;
! 222: zval **value = NULL;
! 223: int what_len, oldval;
! 224: char *oldstr;
! 225:
! 226: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sZ", &what, &what_len, &value) == FAILURE) {
! 227: return;
! 228: }
! 229:
! 230: if (!what) {
! 231: array_init(return_value);
! 232: add_assoc_string(return_value,"line_buffer",SAFE_STRING(rl_line_buffer),1);
! 233: add_assoc_long(return_value,"point",rl_point);
! 234: add_assoc_long(return_value,"end",rl_end);
! 235: #ifdef HAVE_LIBREADLINE
! 236: add_assoc_long(return_value,"mark",rl_mark);
! 237: add_assoc_long(return_value,"done",rl_done);
! 238: add_assoc_long(return_value,"pending_input",rl_pending_input);
! 239: add_assoc_string(return_value,"prompt",SAFE_STRING(rl_prompt),1);
! 240: add_assoc_string(return_value,"terminal_name",(char *)SAFE_STRING(rl_terminal_name),1);
! 241: #endif
! 242: #if HAVE_ERASE_EMPTY_LINE
! 243: add_assoc_long(return_value,"erase_empty_line",rl_erase_empty_line);
! 244: #endif
! 245: add_assoc_string(return_value,"library_version",(char *)SAFE_STRING(rl_library_version),1);
! 246: add_assoc_string(return_value,"readline_name",(char *)SAFE_STRING(rl_readline_name),1);
! 247: } else {
! 248: if (!strcasecmp(what,"line_buffer")) {
! 249: oldstr = rl_line_buffer;
! 250: if (value) {
! 251: /* XXX if (rl_line_buffer) free(rl_line_buffer); */
! 252: convert_to_string_ex(value);
! 253: rl_line_buffer = strdup(Z_STRVAL_PP(value));
! 254: }
! 255: RETVAL_STRING(SAFE_STRING(oldstr),1);
! 256: } else if (!strcasecmp(what, "point")) {
! 257: RETVAL_LONG(rl_point);
! 258: } else if (!strcasecmp(what, "end")) {
! 259: RETVAL_LONG(rl_end);
! 260: #ifdef HAVE_LIBREADLINE
! 261: } else if (!strcasecmp(what, "mark")) {
! 262: RETVAL_LONG(rl_mark);
! 263: } else if (!strcasecmp(what, "done")) {
! 264: oldval = rl_done;
! 265: if (value) {
! 266: convert_to_long_ex(value);
! 267: rl_done = Z_LVAL_PP(value);
! 268: }
! 269: RETVAL_LONG(oldval);
! 270: } else if (!strcasecmp(what, "pending_input")) {
! 271: oldval = rl_pending_input;
! 272: if (value) {
! 273: convert_to_string_ex(value);
! 274: rl_pending_input = Z_STRVAL_PP(value)[0];
! 275: }
! 276: RETVAL_LONG(oldval);
! 277: } else if (!strcasecmp(what, "prompt")) {
! 278: RETVAL_STRING(SAFE_STRING(rl_prompt),1);
! 279: } else if (!strcasecmp(what, "terminal_name")) {
! 280: RETVAL_STRING((char *)SAFE_STRING(rl_terminal_name),1);
! 281: #endif
! 282: #if HAVE_ERASE_EMPTY_LINE
! 283: } else if (!strcasecmp(what, "erase_empty_line")) {
! 284: oldval = rl_erase_empty_line;
! 285: if (value) {
! 286: convert_to_long_ex(value);
! 287: rl_erase_empty_line = Z_LVAL_PP(value);
! 288: }
! 289: RETVAL_LONG(oldval);
! 290: #endif
! 291: } else if (!strcasecmp(what,"library_version")) {
! 292: RETVAL_STRING((char *)SAFE_STRING(rl_library_version),1);
! 293: } else if (!strcasecmp(what, "readline_name")) {
! 294: oldstr = (char*)rl_readline_name;
! 295: if (value) {
! 296: /* XXX if (rl_readline_name) free(rl_readline_name); */
! 297: convert_to_string_ex(value);
! 298: rl_readline_name = strdup(Z_STRVAL_PP(value));;
! 299: }
! 300: RETVAL_STRING(SAFE_STRING(oldstr),1);
! 301: }
! 302: }
! 303: }
! 304:
! 305: /* }}} */
! 306: /* {{{ proto bool readline_add_history(string prompt)
! 307: Adds a line to the history */
! 308: PHP_FUNCTION(readline_add_history)
! 309: {
! 310: char *arg;
! 311: int arg_len;
! 312:
! 313: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
! 314: return;
! 315: }
! 316:
! 317: add_history(arg);
! 318:
! 319: RETURN_TRUE;
! 320: }
! 321:
! 322: /* }}} */
! 323: /* {{{ proto bool readline_clear_history(void)
! 324: Clears the history */
! 325: PHP_FUNCTION(readline_clear_history)
! 326: {
! 327: if (zend_parse_parameters_none() == FAILURE) {
! 328: return;
! 329: }
! 330:
! 331: clear_history();
! 332:
! 333: RETURN_TRUE;
! 334: }
! 335:
! 336: /* }}} */
! 337: /* {{{ proto array readline_list_history(void)
! 338: Lists the history */
! 339: #ifndef HAVE_LIBEDIT
! 340: PHP_FUNCTION(readline_list_history)
! 341: {
! 342: HIST_ENTRY **history;
! 343:
! 344: if (zend_parse_parameters_none() == FAILURE) {
! 345: return;
! 346: }
! 347:
! 348: history = history_list();
! 349:
! 350: array_init(return_value);
! 351:
! 352: if (history) {
! 353: int i;
! 354: for (i = 0; history[i]; i++) {
! 355: add_next_index_string(return_value,history[i]->line,1);
! 356: }
! 357: }
! 358: }
! 359: #endif
! 360: /* }}} */
! 361: /* {{{ proto bool readline_read_history([string filename])
! 362: Reads the history */
! 363: PHP_FUNCTION(readline_read_history)
! 364: {
! 365: char *arg = NULL;
! 366: int arg_len;
! 367:
! 368: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &arg, &arg_len) == FAILURE) {
! 369: return;
! 370: }
! 371:
! 372: /* XXX from & to NYI */
! 373: if (read_history(arg)) {
! 374: RETURN_FALSE;
! 375: } else {
! 376: RETURN_TRUE;
! 377: }
! 378: }
! 379:
! 380: /* }}} */
! 381: /* {{{ proto bool readline_write_history([string filename])
! 382: Writes the history */
! 383: PHP_FUNCTION(readline_write_history)
! 384: {
! 385: char *arg = NULL;
! 386: int arg_len;
! 387:
! 388: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &arg, &arg_len) == FAILURE) {
! 389: return;
! 390: }
! 391:
! 392: if (write_history(arg)) {
! 393: RETURN_FALSE;
! 394: } else {
! 395: RETURN_TRUE;
! 396: }
! 397: }
! 398:
! 399: /* }}} */
! 400: /* {{{ proto bool readline_completion_function(string funcname)
! 401: Readline completion function? */
! 402:
! 403: static char *_readline_command_generator(const char *text, int state)
! 404: {
! 405: HashTable *myht = Z_ARRVAL(_readline_array);
! 406: zval **entry;
! 407:
! 408: if (!state) {
! 409: zend_hash_internal_pointer_reset(myht);
! 410: }
! 411:
! 412: while (zend_hash_get_current_data(myht, (void **)&entry) == SUCCESS) {
! 413: zend_hash_move_forward(myht);
! 414:
! 415: convert_to_string_ex(entry);
! 416: if (strncmp (Z_STRVAL_PP(entry), text, strlen(text)) == 0) {
! 417: return (strdup(Z_STRVAL_PP(entry)));
! 418: }
! 419: }
! 420:
! 421: return NULL;
! 422: }
! 423:
! 424: static zval *_readline_string_zval(const char *str)
! 425: {
! 426: zval *ret;
! 427: int len;
! 428:
! 429: MAKE_STD_ZVAL(ret);
! 430:
! 431: if (str) {
! 432: len = strlen(str);
! 433: ZVAL_STRINGL(ret, (char*)str, len, 1);
! 434: } else {
! 435: ZVAL_NULL(ret);
! 436: }
! 437:
! 438: return ret;
! 439: }
! 440:
! 441: static zval *_readline_long_zval(long l)
! 442: {
! 443: zval *ret;
! 444: MAKE_STD_ZVAL(ret);
! 445:
! 446: Z_TYPE_P(ret) = IS_LONG;
! 447: Z_LVAL_P(ret) = l;
! 448: return ret;
! 449: }
! 450:
! 451: static char **_readline_completion_cb(const char *text, int start, int end)
! 452: {
! 453: zval *params[3];
! 454: int i;
! 455: char **matches = NULL;
! 456: TSRMLS_FETCH();
! 457:
! 458: params[0]=_readline_string_zval(text);
! 459: params[1]=_readline_long_zval(start);
! 460: params[2]=_readline_long_zval(end);
! 461:
! 462: if (call_user_function(CG(function_table), NULL, _readline_completion, &_readline_array, 3, params TSRMLS_CC) == SUCCESS) {
! 463: if (Z_TYPE(_readline_array) == IS_ARRAY) {
! 464: if (zend_hash_num_elements(Z_ARRVAL(_readline_array))) {
! 465: matches = rl_completion_matches(text,_readline_command_generator);
! 466: } else {
! 467: matches = malloc(sizeof(char *) * 2);
! 468: if (!matches) {
! 469: return NULL;
! 470: }
! 471: matches[0] = strdup("");
! 472: matches[1] = '\0';
! 473: }
! 474: }
! 475: }
! 476:
! 477: for (i = 0; i < 3; i++) {
! 478: zval_ptr_dtor(¶ms[i]);
! 479: }
! 480: zval_dtor(&_readline_array);
! 481:
! 482: return matches;
! 483: }
! 484:
! 485: PHP_FUNCTION(readline_completion_function)
! 486: {
! 487: zval *arg = NULL;
! 488: char *name = NULL;
! 489:
! 490: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg)) {
! 491: RETURN_FALSE;
! 492: }
! 493:
! 494: if (!zend_is_callable(arg, 0, &name TSRMLS_CC)) {
! 495: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not callable", name);
! 496: efree(name);
! 497: RETURN_FALSE;
! 498: }
! 499: efree(name);
! 500:
! 501: if (_readline_completion) {
! 502: zval_dtor(_readline_completion);
! 503: FREE_ZVAL(_readline_completion);
! 504: }
! 505:
! 506: MAKE_STD_ZVAL(_readline_completion);
! 507: *_readline_completion = *arg;
! 508: zval_copy_ctor(_readline_completion);
! 509:
! 510: rl_attempted_completion_function = _readline_completion_cb;
! 511: if (rl_attempted_completion_function == NULL) {
! 512: efree(name);
! 513: RETURN_FALSE;
! 514: }
! 515: RETURN_TRUE;
! 516: }
! 517:
! 518: /* }}} */
! 519:
! 520: #if HAVE_RL_CALLBACK_READ_CHAR
! 521:
! 522: static void php_rl_callback_handler(char *the_line)
! 523: {
! 524: zval *params[1];
! 525: zval dummy;
! 526: TSRMLS_FETCH();
! 527:
! 528: ZVAL_NULL(&dummy);
! 529:
! 530: params[0] = _readline_string_zval(the_line);
! 531:
! 532: call_user_function(CG(function_table), NULL, _prepped_callback, &dummy, 1, params TSRMLS_CC);
! 533:
! 534: zval_ptr_dtor(¶ms[0]);
! 535: zval_dtor(&dummy);
! 536: }
! 537:
! 538: /* {{{ proto void readline_callback_handler_install(string prompt, mixed callback)
! 539: Initializes the readline callback interface and terminal, prints the prompt and returns immediately */
! 540: PHP_FUNCTION(readline_callback_handler_install)
! 541: {
! 542: zval *callback;
! 543: char *name = NULL;
! 544: char *prompt;
! 545: int prompt_len;
! 546:
! 547: if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &prompt, &prompt_len, &callback)) {
! 548: return;
! 549: }
! 550:
! 551: if (!zend_is_callable(callback, 0, &name TSRMLS_CC)) {
! 552: php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not callable", name);
! 553: efree(name);
! 554: RETURN_FALSE;
! 555: }
! 556: efree(name);
! 557:
! 558: if (_prepped_callback) {
! 559: rl_callback_handler_remove();
! 560: zval_dtor(_prepped_callback);
! 561: FREE_ZVAL(_prepped_callback);
! 562: }
! 563:
! 564: MAKE_STD_ZVAL(_prepped_callback);
! 565: *_prepped_callback = *callback;
! 566: zval_copy_ctor(_prepped_callback);
! 567:
! 568: rl_callback_handler_install(prompt, php_rl_callback_handler);
! 569:
! 570: RETURN_TRUE;
! 571: }
! 572: /* }}} */
! 573:
! 574: /* {{{ proto void readline_callback_read_char()
! 575: Informs the readline callback interface that a character is ready for input */
! 576: PHP_FUNCTION(readline_callback_read_char)
! 577: {
! 578: if (_prepped_callback) {
! 579: rl_callback_read_char();
! 580: }
! 581: }
! 582: /* }}} */
! 583:
! 584: /* {{{ proto bool readline_callback_handler_remove()
! 585: Removes a previously installed callback handler and restores terminal settings */
! 586: PHP_FUNCTION(readline_callback_handler_remove)
! 587: {
! 588: if (_prepped_callback) {
! 589: rl_callback_handler_remove();
! 590: zval_dtor(_prepped_callback);
! 591: FREE_ZVAL(_prepped_callback);
! 592: _prepped_callback = 0;
! 593: RETURN_TRUE;
! 594: }
! 595: RETURN_FALSE;
! 596: }
! 597: /* }}} */
! 598:
! 599: /* {{{ proto void readline_redisplay(void)
! 600: Ask readline to redraw the display */
! 601: PHP_FUNCTION(readline_redisplay)
! 602: {
! 603: rl_redisplay();
! 604: }
! 605: /* }}} */
! 606:
! 607: /* {{{ proto void readline_on_new_line(void)
! 608: Inform readline that the cursor has moved to a new line */
! 609: PHP_FUNCTION(readline_on_new_line)
! 610: {
! 611: rl_on_new_line();
! 612: }
! 613: /* }}} */
! 614:
! 615: #endif
! 616:
! 617:
! 618: #endif /* HAVE_LIBREADLINE */
! 619:
! 620: /*
! 621: * Local variables:
! 622: * tab-width: 4
! 623: * c-basic-offset: 4
! 624: * End:
! 625: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>