Home | History | Annotate | Line # | Download | only in memswitch
methods.c revision 1.5.30.1
      1 /*	$NetBSD: methods.c,v 1.5.30.1 2008/05/18 12:36:20 yamt Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Minoura Makoto.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <stdio.h>
     33 #include <string.h>
     34 #include <err.h>
     35 #include <sys/types.h>
     36 
     37 #include "memswitch.h"
     38 #include "methods.h"
     39 
     40 int
     41 atoi_ (p)
     42 	 const char **p;
     43 {
     44 	const char *p1 = *p;
     45 	int v = 0;
     46 	int first = 1;
     47 
     48 	while (*p1 == ' ' || *p1 == '\t')
     49 		p1++;
     50 
     51 	if (*p1 == 0) {
     52 		*p = 0;
     53 		return 0;
     54 	}
     55 	if (strlen (p1) >= 2 && strncasecmp ("0x", p1, 2) == 0) {
     56 		p1 += 2;
     57 		while (1) {
     58 			if (*p1 >= '0' && *p1 <= '9') {
     59 				v *= 16;
     60 				v += *p1 - '0';
     61 				first = 0;
     62 			} else if (*p1 >= 'A' && *p1 <= 'F') {
     63 				v *= 16;
     64 				v += *p1 - 'A' + 10;
     65 				first = 0;
     66 			} else if (*p1 >= 'a' && *p1 <= 'f') {
     67 				v *= 16;
     68 				v += *p1 - 'a' + 10;
     69 				first = 0;
     70 			} else {
     71 				break;
     72 			}
     73 			p1++;
     74 		}
     75 	} else {
     76 		while (1) {
     77 			if (*p1 >= '0' && *p1 <= '9') {
     78 				v *= 10;
     79 				v += *p1 - '0';
     80 				first = 0;
     81 			} else {
     82 				break;
     83 			}
     84 			p1++;
     85 		}
     86 	}
     87 
     88 	if (first) {
     89 		*p = 0;
     90 		return 0;
     91 	}
     92 
     93 	while (*p1 == ' ' || *p1 == '\t') p1++;
     94 	*p = p1;
     95 	return v;
     96 }
     97 
     98 int
     99 fill_uchar (prop)
    100 	struct property *prop;
    101 {
    102 	if (current_values == 0)
    103 		alloc_current_values ();
    104 
    105 	prop->current_value.byte[0] = current_values[prop->offset];
    106 	prop->current_value.byte[1] = 0;
    107 	prop->current_value.byte[2] = 0;
    108 	prop->current_value.byte[3] = 0;
    109 	prop->value_valid = 1;
    110 
    111 	return 0;
    112 }
    113 
    114 int
    115 fill_ushort (prop)
    116 	struct property *prop;
    117 {
    118 	if (current_values == 0)
    119 		alloc_current_values ();
    120 
    121 	prop->current_value.byte[0] = current_values[prop->offset];
    122 	prop->current_value.byte[1] = current_values[prop->offset+1];
    123 	prop->current_value.byte[2] = 0;
    124 	prop->current_value.byte[3] = 0;
    125 	prop->value_valid = 1;
    126 
    127 	return 0;
    128 }
    129 
    130 int
    131 fill_ulong (prop)
    132 	struct property *prop;
    133 {
    134 	if (current_values == 0)
    135 		alloc_current_values ();
    136 
    137 	prop->current_value.byte[0] = current_values[prop->offset];
    138 	prop->current_value.byte[1] = current_values[prop->offset+1];
    139 	prop->current_value.byte[2] = current_values[prop->offset+2];
    140 	prop->current_value.byte[3] = current_values[prop->offset+3];
    141 	prop->value_valid = 1;
    142 
    143 	return 0;
    144 }
    145 
    146 int
    147 flush_uchar (prop)
    148 	struct property *prop;
    149 {
    150 	if (!prop->modified)
    151 		return 0;
    152 
    153 	if (modified_values == 0)
    154 		alloc_modified_values ();
    155 
    156 	modified_values[prop->offset] = prop->modified_value.byte[0];
    157 
    158 	return 0;
    159 }
    160 
    161 int
    162 flush_ushort (prop)
    163 	struct property *prop;
    164 {
    165 	if (!prop->modified)
    166 		return 0;
    167 
    168 	if (modified_values == 0)
    169 		alloc_modified_values ();
    170 
    171 	modified_values[prop->offset] = prop->modified_value.byte[0];
    172 	modified_values[prop->offset+1] = prop->modified_value.byte[1];
    173 
    174 	return 0;
    175 }
    176 
    177 int
    178 flush_ulong (prop)
    179 	struct property *prop;
    180 {
    181 	if (!prop->modified)
    182 		return 0;
    183 
    184 	if (modified_values == 0)
    185 		alloc_modified_values ();
    186 
    187 	modified_values[prop->offset] = prop->modified_value.byte[0];
    188 	modified_values[prop->offset+1] = prop->modified_value.byte[1];
    189 	modified_values[prop->offset+2] = prop->modified_value.byte[2];
    190 	modified_values[prop->offset+3] = prop->modified_value.byte[3];
    191 
    192 	return 0;
    193 }
    194 
    195 int
    196 flush_dummy (prop)
    197 	struct property *prop;
    198 {
    199 	return 0;
    200 }
    201 
    202 int
    203 parse_dummy (prop, value)
    204 	struct property *prop;
    205 	const char *value;
    206 {
    207 	warnx ("Cannot modify %s.%s", prop->class, prop->node);
    208 
    209 	return -1;
    210 }
    211 
    212 int
    213 parse_byte (prop, value)
    214 	struct property *prop;
    215 	const char *value;
    216 {
    217 	const char *p = value;
    218 	int v;
    219 
    220 	v = atoi_ (&p);
    221 	if (p == 0) {
    222 		warnx ("%s: Invalid value", value);
    223 		return -1;
    224 	}
    225 
    226 	if (strcasecmp ("MB", p) == 0)
    227 		v *= 1024 * 1024;
    228 	else if (strcasecmp ("KB", p) == 0)
    229 		v *= 1024;
    230 	else if (*p != 0 &&
    231 		 strcasecmp ("B", p) != 0) {
    232 		warnx ("%s: Invalid value", value);
    233 		return -1;
    234 	}
    235 
    236 	if (v < prop->min) {
    237 		warnx ("%s: Too small", value);
    238 		return -1;
    239 	} else if (v > prop->max) {
    240 		warnx ("%s: Too large", value);
    241 		return -1;
    242 	}
    243 
    244 	prop->modified = 1;
    245 	prop->modified_value.longword = v;
    246 
    247 	return 0;
    248 }
    249 
    250 int
    251 parse_uchar (prop, value)
    252 	struct property *prop;
    253 	const char *value;
    254 {
    255 	const char *p = value;
    256 	int v;
    257 
    258 	v = atoi_ (&p);
    259 	if (p == 0) {
    260 		warnx ("%s: Invalid value", value);
    261 		return -1;
    262 	}
    263 
    264 	if (v < prop->min) {
    265 		warnx ("%s: Too small", value);
    266 		return -1;
    267 	} else if (v > prop->max) {
    268 		warnx ("%s: Too large", value);
    269 		return -1;
    270 	}
    271 
    272 	prop->modified = 1;
    273 	prop->modified_value.byte[0] = v;
    274 
    275 	return 0;
    276 }
    277 
    278 int
    279 parse_ulong (prop, value)
    280 	struct property *prop;
    281 	const char *value;
    282 {
    283 	const char *p = value;
    284 	int v;
    285 
    286 	v = atoi_ (&p);
    287 	if (p == 0) {
    288 		warnx ("%s: Invalid value", value);
    289 		return -1;
    290 	}
    291 
    292 	if (v < prop->min) {
    293 		warnx ("%s: Too small", value);
    294 		return -1;
    295 	} else if (v > prop->max) {
    296 		warnx ("%s: Too large", value);
    297 		return -1;
    298 	}
    299 
    300 	prop->modified = 1;
    301 	prop->modified_value.longword = v;
    302 
    303 	return 0;
    304 }
    305 
    306 int
    307 parse_ushort (prop, value)
    308 	struct property *prop;
    309 	const char *value;
    310 {
    311 	const char *p = value;
    312 	int v;
    313 
    314 	v = atoi_ (&p);
    315 	if (p == 0) {
    316 		warnx ("%s: Invalid value", value);
    317 		return -1;
    318 	}
    319 
    320 	if (v < prop->min) {
    321 		warnx ("%s: Too small", value);
    322 		return -1;
    323 	} else if (v > prop->max) {
    324 		warnx ("%s: Too large", value);
    325 		return -1;
    326 	}
    327 
    328 	prop->modified = 1;
    329 	prop->modified_value.word[0] = v;
    330 
    331 	return 0;
    332 }
    333 
    334 int
    335 parse_time (prop, value)
    336 	struct property *prop;
    337 	const char *value;
    338 {
    339 	const char *p = value;
    340 	int v;
    341 
    342 	while (*p == ' ' || *p == '\t') p++;
    343 	if (*p == '-') {
    344 		p++;
    345 		v = -atoi_ (&p);
    346 	} else
    347 		v = atoi_ (&p);
    348 	if (p == 0) {
    349 		warnx ("%s: Invalid value", value);
    350 		return -1;
    351 	}
    352 
    353 	if (strcasecmp ("hours", p) == 0 || strcasecmp ("hour", p) == 0)
    354 		v *= 60 * 60;
    355 	else if (strcasecmp ("minutes", p) == 0 ||
    356 		 strcasecmp ("minute", p) == 0)
    357 		v *= 60;
    358 	else if (*p != 0 &&
    359 		 strcasecmp ("second", p) != 0 &&
    360 		 strcasecmp ("seconds", p) != 0) {
    361 		warnx ("%s: Invalid value", value);
    362 		return -1;
    363 	}
    364 
    365 	if (v < prop->min) {
    366 		warnx ("%s: Too small", value);
    367 		return -1;
    368 	} else if (v > prop->max) {
    369 		warnx ("%s: Too large", value);
    370 		return -1;
    371 	}
    372 
    373 	prop->modified = 1;
    374 	prop->modified_value.longword = v;
    375 
    376 	return 0;
    377 }
    378 
    379 int
    380 parse_bootdev (prop, value)
    381 	struct property *prop;
    382 	const char *value;
    383 {
    384 	const char *p = value;
    385 	int v;
    386 	char expr_scsi[32];
    387 
    388 	while (*p == ' ' || *p == '\t') p++;
    389 
    390 	if (strcasecmp ("STD", p) == 0)
    391 		v = 0;
    392 	else if (strcasecmp ("ROM", p) == 0)
    393 		v = 0xa000;
    394 	else if (strcasecmp ("RAM", p) == 0)
    395 		v = 0xb000;
    396 	else if (strncasecmp ("HD", p, 2) == 0) {
    397 		p += 2;
    398 		v = atoi_ (&p);
    399 		if (p == 0 || v < 0 || v > 15) {
    400 			warnx ("%s: Invalid value", value);
    401 			return -1;
    402 		}
    403 		v *= 0x0100;
    404 		v += 0x8000;
    405 	} else if (strncasecmp ("FD", p, 2) == 0) {
    406 		p += 2;
    407 		v = atoi_ (&p);
    408 		if (p == 0 || v < 0 || v > 3) {
    409 			warnx ("%s: Invalid value", value);
    410 			return -1;
    411 		}
    412 		v *= 0x0100;
    413 		v += 0x9070;
    414 	} else if (strncasecmp ("INSCSI", p, 6) == 0 ||
    415 		   strncasecmp ("EXSCSI", p, 6) == 0) {
    416 		int isin = strncasecmp ("EXSCSI", p, 6);
    417 
    418 		p += 6;
    419 		v = atoi_ (&p);
    420 		if (p == 0 || v < 0 || v > 7) {
    421 			warnx ("%s: Invalid value", value);
    422 			return -1;
    423 		}
    424 
    425 		/* change boot.romaddr */
    426 		sprintf(expr_scsi, "boot.romaddr=0x%06x",
    427 			(isin ? 0xfc0000 : 0xea0020) + v * 4);
    428 		modify_single(expr_scsi);
    429 
    430 		/* boot.device again */
    431 		v = 0xa000;
    432 	} else {
    433 		warnx ("%s: Invalid value", value);
    434 		return -1;
    435 	}
    436 
    437 	prop->modified = 1;
    438 	prop->modified_value.word[0] = v;
    439 
    440 	return 0;
    441 }
    442 
    443 int
    444 parse_serial (prop, value)
    445 	struct property *prop;
    446 	const char *value;
    447 #define NEXTSPEC	while (*p == ' ' || *p == '\t') p++;		\
    448 			if (*p++ != ',') {				\
    449 				warnx ("%s: Invalid value", value);	\
    450 				return -1;				\
    451 			}						\
    452 			while (*p == ' ' || *p == '\t') p++;
    453 {
    454 	const char *p = value;
    455 	const char *q;
    456 	int baud, bit, parity, stop, flow;
    457 	static const int bauds[] = {75, 150, 300, 600, 1200, 2400, 4800, 9600,
    458 	    17361, 0};
    459 	static const char parities[] = "noe";
    460 	int i;
    461 
    462 	while (*p == ' ' || *p == '\t') p++;
    463 
    464 	/* speed */
    465 	baud = atoi_ (&p);
    466 	if (p == 0) {
    467 		warnx ("%s: Invalid value", value);
    468 		return -1;
    469 	}
    470 	for (i = 0; bauds[i]; i++)
    471 		if (baud == bauds[i])
    472 			break;
    473 	if (bauds[i] == 0) {
    474 		warnx ("%d: Invalid speed", baud);
    475 		return -1;
    476 	}
    477 	baud = i;
    478 
    479 	NEXTSPEC;
    480 
    481 	/* bit size */
    482 	if (*p < '5' || *p > '8') {
    483 		warnx ("%c: Invalid bit size", *p);
    484 		return -1;
    485 	}
    486 	bit = *p++ - '5';
    487 
    488 	NEXTSPEC;
    489 
    490 	/* parity */
    491 	q = strchr(parities, *p++);
    492 	if (q == 0) {
    493 		warnx ("%c: Invalid parity spec", *p);
    494 		return -1;
    495 	}
    496 	parity = q - parities;
    497 
    498 	NEXTSPEC;
    499 
    500 	/* stop bit */
    501 	if (strncmp (p, "1.5", 3) == 0) {
    502 		stop = 2;
    503 		p += 3;
    504 	} else if (strncmp (p, "2", 1) == 0) {
    505 		stop = 0;
    506 		p++;
    507 	} else if (strncmp (p, "1", 1) == 0) {
    508 		stop = 1;
    509 		p++;
    510 	} else {
    511 		warnx ("%s: Invalid value", value);
    512 		return -1;
    513 	}
    514 
    515 	NEXTSPEC;
    516 
    517 	/* flow */
    518 	if (*p == '-')
    519 		flow = 0;
    520 	else if (*p == 's')
    521 		flow = 1;
    522 	else {
    523 		warnx ("%s: Invalid value", value);
    524 		return -1;
    525 	}
    526 
    527 	p++;
    528 	while (*p == ' ' || *p == '\t') p++;
    529 	if (*p != 0) {
    530 		warnx ("%s: Invalid value", value);
    531 		return -1;
    532 	}
    533 
    534 	prop->modified = 1;
    535 	prop->modified_value.word[0] = ((stop << 14) +
    536 					(parity << 12) +
    537 					(bit << 10) +
    538 					(flow << 9) +
    539 					baud);
    540 
    541 	return 0;
    542 }
    543 #undef NEXTSPEC
    544 
    545 int
    546 parse_srammode (prop, value)
    547 	struct property *prop;
    548 	const char *value;
    549 {
    550 	static const char *const sramstrs[] = {"unused", "SRAMDISK", "program"};
    551 	int i;
    552 
    553 	for (i = 0; i <= 2; i++) {
    554 		if (strcasecmp (value, sramstrs[i]) == 0)
    555 			break;
    556 	}
    557 	if (i > 2) {
    558 		warnx ("%s: Invalid value", value);
    559 		return -1;
    560 	}
    561 
    562 	prop->modified = 1;
    563 	prop->modified_value.byte[0] = i;
    564 
    565 	return 0;
    566 }
    567 
    568 int
    569 print_uchar (prop, str)
    570 	struct property *prop;
    571 	char *str;
    572 {
    573 	if (prop->modified)
    574 		snprintf (str, MAXVALUELEN,
    575 			  "%d", prop->modified_value.byte[0]);
    576 	else {
    577 		if (!prop->value_valid)
    578 			prop->fill (prop);
    579 		snprintf (str, MAXVALUELEN, "%d",
    580 			  prop->current_value.byte[0]);
    581 	}
    582 
    583 	return 0;
    584 }
    585 
    586 int
    587 print_ucharh (prop, str)
    588 	struct property *prop;
    589 	char *str;
    590 {
    591 	if (prop->modified)
    592 		snprintf (str, MAXVALUELEN,
    593 			  "0x%4.4x", prop->modified_value.byte[0]);
    594 	else {
    595 		if (!prop->value_valid)
    596 			prop->fill (prop);
    597 		snprintf (str, MAXVALUELEN,
    598 			  "0x%4.4x", prop->current_value.byte[0]);
    599 	}
    600 
    601 	return 0;
    602 }
    603 
    604 int
    605 print_ushorth (prop, str)
    606 	struct property *prop;
    607 	char *str;
    608 {
    609 	if (prop->modified)
    610 		snprintf (str, MAXVALUELEN,
    611 			  "0x%4.4x", prop->modified_value.word[0]);
    612 	else {
    613 		if (!prop->value_valid)
    614 			prop->fill (prop);
    615 		snprintf (str, MAXVALUELEN,
    616 			  "0x%4.4x", prop->current_value.word[0]);
    617 	}
    618 
    619 	return 0;
    620 }
    621 
    622 int
    623 print_ulong (prop, str)
    624 	struct property *prop;
    625 	char *str;
    626 {
    627 	if (prop->modified)
    628 		snprintf (str, MAXVALUELEN,
    629 			  "%ld", prop->modified_value.longword);
    630 	else {
    631 		if (!prop->value_valid)
    632 			prop->fill (prop);
    633 		snprintf (str, MAXVALUELEN,
    634 			  "%ld", prop->current_value.longword);
    635 	}
    636 
    637 	return 0;
    638 }
    639 
    640 int
    641 print_ulongh (prop, str)
    642 	struct property *prop;
    643 	char *str;
    644 {
    645 	if (prop->modified)
    646 		snprintf (str, MAXVALUELEN,
    647 			  "0x%8.8lx", prop->modified_value.longword);
    648 	else {
    649 		if (!prop->value_valid)
    650 			prop->fill (prop);
    651 		snprintf (str, MAXVALUELEN,
    652 			  "0x%8.8lx", prop->current_value.longword);
    653 	}
    654 
    655 	return 0;
    656 }
    657 
    658 int
    659 print_magic (prop, str)
    660 	struct property *prop;
    661 	char *str;
    662 {
    663 	if (!prop->value_valid)
    664 		prop->fill (prop);
    665 	snprintf (str, MAXVALUELEN, "%c%c%c%c",
    666 		  prop->current_value.byte[0],
    667 		  prop->current_value.byte[1],
    668 		  prop->current_value.byte[2],
    669 		  prop->current_value.byte[3]);
    670 
    671 	return 0;
    672 }
    673 
    674 int
    675 print_timesec (prop, str)
    676 	struct property *prop;
    677 	char *str;
    678 {
    679 	if (prop->modified)
    680 		snprintf (str, MAXVALUELEN,
    681 			  "%ld second", prop->modified_value.longword);
    682 	else {
    683 		if (!prop->value_valid)
    684 			prop->fill (prop);
    685 		snprintf (str, MAXVALUELEN,
    686 			  "%ld second", prop->current_value.longword);
    687 	}
    688 
    689 	return 0;
    690 }
    691 
    692 int
    693 print_bootdev (prop, str)
    694 	struct property *prop;
    695 	char *str;
    696 {
    697 	unsigned int v;
    698 
    699 	if (prop->modified)
    700 		v = prop->modified_value.word[0];
    701 	else {
    702 		if (!prop->value_valid)
    703 			prop->fill (prop);
    704 		v = prop->current_value.word[0];
    705 	}
    706 
    707 	if (v == 0)
    708 		strcpy (str, "STD");
    709 	else if (v == 0xa000)
    710 		strcpy (str, "ROM");
    711 	else if (v == 0xb000)
    712 		strcpy (str, "RAM");
    713 	else if (v >= 0x8000 && v < 0x9000)
    714 		snprintf (str, MAXVALUELEN, "HD%d", (v & 0x0f00) >> 8);
    715 	else if (v >= 0x9000 && v < 0xa000)
    716 		snprintf (str, MAXVALUELEN, "FD%d", (v & 0x0f00) >> 8);
    717 	else
    718 		snprintf (str, MAXVALUELEN, "%8.8x", v);
    719 
    720 	return 0;
    721 }
    722 
    723 int
    724 print_serial (prop, str)
    725 	struct property *prop;
    726 	char *str;
    727 {
    728 	unsigned int v;
    729 	const char *baud, *stop;
    730 	char bit, parity, flow;
    731 	static const char *const bauds[] = {"75", "150", "300", "600", "1200",
    732 			       "2400", "4800", "9600", "17361"};
    733 	static const char bits[] = "5678";
    734 	static const char parities[] = "noen";
    735 	static const char *const stops[] = {"2", "1", "1.5", "2"};
    736 	static const char flows[] = "-s";
    737 
    738 	if (prop->modified)
    739 		v = prop->modified_value.word[0];
    740 	else {
    741 		if (!prop->value_valid)
    742 			prop->fill (prop);
    743 		v = prop->current_value.word[0];
    744 	}
    745 
    746 	baud = bauds[v & 0x000f];
    747 	bit = bits[(v & 0x0c00) >> 10];
    748 	parity = parities[(v & 0x3000) >> 12];
    749 	stop = stops[(v & 0xe000) >> 14];
    750 	flow = flows[(v & 0x0200) >> 9];
    751 	sprintf (str, "%s,%c,%c,%s,%c", baud, bit, parity, stop, flow);
    752 
    753 	return 0;
    754 }
    755 
    756 int
    757 print_srammode (prop, str)
    758 	struct property *prop;
    759 	char *str;
    760 {
    761 	int v;
    762 	static const char *const sramstrs[] = {"unused", "SRAMDISK", "program"};
    763 
    764 	if (prop->modified)
    765 		v = prop->modified_value.byte[0];
    766 	else {
    767 		if (!prop->value_valid)
    768 			prop->fill (prop);
    769 		v = prop->current_value.byte[0];
    770 	}
    771 
    772 	if (v < 0 || v > 2)
    773 		strcpy (str, "INVALID");
    774 	else
    775 		strcpy (str, sramstrs[v]);
    776 
    777 	return 0;
    778 }
    779