blob: 10d5a8d63159790ec3bccc9c08961b922b146fe1 [file] [log] [blame]
Glenn L McGrath60281112001-11-02 11:39:46 +00001/*
2 * Support code for the hexdump and od applets,
3 * based on code from util-linux v 2.11l
4 *
5 * Copyright (c) 1989
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Original copyright notice is retained at the end of this file.
23 */
24
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h> /* for isdigit() */
28#include "dump.h"
29#include "libbb.h"
30
31enum _vflag vflag = FIRST;
32FS *fshead; /* head of format strings */
33extern FS *fshead; /* head of format strings */
34extern int blocksize;
35static FU *endfu;
36static char **_argv;
37static off_t savaddress; /* saved address/offset in stream */
38static off_t eaddress; /* end address */
39static off_t address; /* address/offset in stream */
40off_t skip; /* bytes to skip */
41off_t saveaddress;
42int exitval; /* final exit value */
43int blocksize; /* data block size */
44int length = -1; /* max bytes to read */
45
46
47int size(FS *fs)
48{
49 register FU *fu;
50 register int bcnt, cursize;
51 register char *fmt;
52 int prec;
53
54 /* figure out the data block size needed for each format unit */
55 for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
56 if (fu->bcnt) {
57 cursize += fu->bcnt * fu->reps;
58 continue;
59 }
60 for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
61 if (*fmt != '%')
62 continue;
63 /*
64 * skip any special chars -- save precision in
65 * case it's a %s format.
66 */
67 while (index(".#-+ 0123456789" + 1, *++fmt));
68 if (*fmt == '.' && isdigit(*++fmt)) {
69 prec = atoi(fmt);
70 while (isdigit(*++fmt));
71 }
72 switch(*fmt) {
73 case 'c':
74 bcnt += 1;
75 break;
76 case 'd': case 'i': case 'o': case 'u':
77 case 'x': case 'X':
78 bcnt += 4;
79 break;
80 case 'e': case 'E': case 'f': case 'g': case 'G':
81 bcnt += 8;
82 break;
83 case 's':
84 bcnt += prec;
85 break;
86 case '_':
87 switch(*++fmt) {
88 case 'c': case 'p': case 'u':
89 bcnt += 1;
90 break;
91 }
92 }
93 }
94 cursize += bcnt * fu->reps;
95 }
96 return(cursize);
97}
98
99void rewrite(FS *fs)
100{
101 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
102 register PR *pr, **nextpr = NULL;
103 register FU *fu;
104 register char *p1, *p2;
105 char savech, *fmtp;
106 int nconv, prec = 0;
107
108 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
109 /*
110 * break each format unit into print units; each
111 * conversion character gets its own.
112 */
113 for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
114 /* NOSTRICT */
115 pr = (PR *)xmalloc(sizeof(PR));
116 if (!fu->nextpr)
117 fu->nextpr = pr;
118 else
119 *nextpr = pr;
120
121 /* skip preceding text and up to the next % sign */
122 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
123
124 /* only text in the string */
125 if (!*p1) {
126 pr->fmt = fmtp;
127 pr->flags = F_TEXT;
128 break;
129 }
130
131 /*
132 * get precision for %s -- if have a byte count, don't
133 * need it.
134 */
135 if (fu->bcnt) {
136 sokay = USEBCNT;
137 /* skip to conversion character */
138 for (++p1; index(".#-+ 0123456789", *p1); ++p1);
139 } else {
140 /* skip any special chars, field width */
141 while (index(".#-+ 0123456789" + 1, *++p1));
142 if (*p1 == '.' && isdigit(*++p1)) {
143 sokay = USEPREC;
144 prec = atoi(p1);
145 while (isdigit(*++p1));
146 }
147 else
148 sokay = NOTOKAY;
149 }
150
151 p2 = p1 + 1; /* set end pointer */
152
153 /*
154 * figure out the byte count for each conversion;
155 * rewrite the format as necessary, set up blank-
156 * padding for end of data.
157 */
158 switch(*p1) {
159 case 'c':
160 pr->flags = F_CHAR;
161 switch(fu->bcnt) {
162 case 0: case 1:
163 pr->bcnt = 1;
164 break;
165 default:
166 p1[1] = '\0';
167 error_msg_and_die("bad byte count for conversion character %s.", p1);
168 }
169 break;
170 case 'd': case 'i':
171 pr->flags = F_INT;
172 goto sw1;
173 case 'l':
174 ++p2;
175 switch(p1[1]) {
176 case 'd': case 'i':
177 ++p1;
178 pr->flags = F_INT;
179 goto sw1;
180 case 'o': case 'u': case 'x': case 'X':
181 ++p1;
182 pr->flags = F_UINT;
183 goto sw1;
184 default:
185 p1[2] = '\0';
186 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
187 }
188 /* NOTREACHED */
189 case 'o': case 'u': case 'x': case 'X':
190 pr->flags = F_UINT;
191sw1: switch(fu->bcnt) {
192 case 0: case 4:
193 pr->bcnt = 4;
194 break;
195 case 1:
196 pr->bcnt = 1;
197 break;
198 case 2:
199 pr->bcnt = 2;
200 break;
201 default:
202 p1[1] = '\0';
203 error_msg_and_die("bad byte count for conversion character %s.", p1);
204 }
205 break;
206 case 'e': case 'E': case 'f': case 'g': case 'G':
207 pr->flags = F_DBL;
208 switch(fu->bcnt) {
209 case 0: case 8:
210 pr->bcnt = 8;
211 break;
212 case 4:
213 pr->bcnt = 4;
214 break;
215 default:
216 p1[1] = '\0';
217 error_msg_and_die("bad byte count for conversion character %s.", p1);
218 }
219 break;
220 case 's':
221 pr->flags = F_STR;
222 switch(sokay) {
223 case NOTOKAY:
224 error_msg_and_die("%%s requires a precision or a byte count.");
225 case USEBCNT:
226 pr->bcnt = fu->bcnt;
227 break;
228 case USEPREC:
229 pr->bcnt = prec;
230 break;
231 }
232 break;
233 case '_':
234 ++p2;
235 switch(p1[1]) {
236 case 'A':
237 endfu = fu;
238 fu->flags |= F_IGNORE;
239 /* FALLTHROUGH */
240 case 'a':
241 pr->flags = F_ADDRESS;
242 ++p2;
243 switch(p1[2]) {
244 case 'd': case 'o': case'x':
245 *p1 = p1[2];
246 break;
247 default:
248 p1[3] = '\0';
249 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
250 }
251 break;
252 case 'c':
253 pr->flags = F_C;
254 /* *p1 = 'c'; set in conv_c */
255 goto sw2;
256 case 'p':
257 pr->flags = F_P;
258 *p1 = 'c';
259 goto sw2;
260 case 'u':
261 pr->flags = F_U;
262 /* *p1 = 'c'; set in conv_u */
263sw2: switch(fu->bcnt) {
264 case 0: case 1:
265 pr->bcnt = 1;
266 break;
267 default:
268 p1[2] = '\0';
269 error_msg_and_die("bad byte count for conversion character %s.", p1);
270 }
271 break;
272 default:
273 p1[2] = '\0';
274 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
275 }
276 break;
277 default:
278 p1[1] = '\0';
279 error_msg_and_die("hexdump: bad conversion character %%%s.\n", p1);
280 }
281
282 /*
283 * copy to PR format string, set conversion character
284 * pointer, update original.
285 */
286 savech = *p2;
287 p1[1] = '\0';
288 if (!(pr->fmt = strdup(fmtp)))
289 perror_msg_and_die("hexdump");
290 *p2 = savech;
291 pr->cchar = pr->fmt + (p1 - fmtp);
292 fmtp = p2;
293
294 /* only one conversion character if byte count */
295 if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) {
296 error_msg_and_die("hexdump: byte count with multiple conversion characters.\n");
297 }
298 }
299 /*
300 * if format unit byte count not specified, figure it out
301 * so can adjust rep count later.
302 */
303 if (!fu->bcnt)
304 for (pr = fu->nextpr; pr; pr = pr->nextpr)
305 fu->bcnt += pr->bcnt;
306 }
307 /*
308 * if the format string interprets any data at all, and it's
309 * not the same as the blocksize, and its last format unit
310 * interprets any data at all, and has no iteration count,
311 * repeat it as necessary.
312 *
313 * if, rep count is greater than 1, no trailing whitespace
314 * gets output from the last iteration of the format unit.
315 */
316 for (fu = fs->nextfu;; fu = fu->nextfu) {
317 if (!fu->nextfu && fs->bcnt < blocksize &&
318 !(fu->flags&F_SETREP) && fu->bcnt)
319 fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
320 if (fu->reps > 1) {
321 for (pr = fu->nextpr;; pr = pr->nextpr)
322 if (!pr->nextpr)
323 break;
324 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
325 p2 = isspace(*p1) ? p1 : NULL;
326 if (p2)
327 pr->nospace = p2;
328 }
329 if (!fu->nextfu)
330 break;
331 }
332}
333
334static void doskip(char *fname, int statok)
335{
336 struct stat sbuf;
337
338 if (statok) {
339 if (fstat(fileno(stdin), &sbuf)) {
340 perror_msg_and_die("hexdump: %s", fname);
341 }
342 if ( ( ! (S_ISCHR(sbuf.st_mode) ||
343 S_ISBLK(sbuf.st_mode) ||
344 S_ISFIFO(sbuf.st_mode)) ) &&
345 skip >= sbuf.st_size) {
346 /* If size valid and skip >= size */
347 skip -= sbuf.st_size;
348 address += sbuf.st_size;
349 return;
350 }
351 }
352 if (fseek(stdin, skip, SEEK_SET)) {
353 perror_msg_and_die("hexdump: %s", fname);
354 }
355 savaddress = address += skip;
356 skip = 0;
357}
358
359int next(char **argv)
360{
361 static int done;
362 int statok;
363
364 if (argv) {
365 _argv = argv;
366 return(1);
367 }
368 for (;;) {
369 if (*_argv) {
370 if (!(freopen(*_argv, "r", stdin))) {
371 perror_msg("%s", *_argv);
372 exitval = 1;
373 ++_argv;
374 continue;
375 }
376 statok = done = 1;
377 } else {
378 if (done++)
379 return(0);
380 statok = 0;
381 }
382 if (skip)
383 doskip(statok ? *_argv : "stdin", statok);
384 if (*_argv)
385 ++_argv;
386 if (!skip)
387 return(1);
388 }
389 /* NOTREACHED */
390}
391
392static u_char *
393get(void)
394{
395 static int ateof = 1;
396 static u_char *curp, *savp;
397 register int n;
398 int need, nread;
399 u_char *tmpp;
400
401 if (!curp) {
402 curp = (u_char *)xmalloc(blocksize);
403 savp = (u_char *)xmalloc(blocksize);
404 } else {
405 tmpp = curp;
406 curp = savp;
407 savp = tmpp;
408 address = savaddress += blocksize;
409 }
410 for (need = blocksize, nread = 0;;) {
411 /*
412 * if read the right number of bytes, or at EOF for one file,
413 * and no other files are available, zero-pad the rest of the
414 * block and set the end flag.
415 */
416 if (!length || (ateof && !next((char **)NULL))) {
417 if (need == blocksize) {
418 return((u_char *)NULL);
419 }
420 if (vflag != ALL && !bcmp(curp, savp, nread)) {
421 if (vflag != DUP) {
422 printf("*\n");
423 }
424 return((u_char *)NULL);
425 }
426 bzero((char *)curp + nread, need);
427 eaddress = address + nread;
428 return(curp);
429 }
430 n = fread((char *)curp + nread, sizeof(u_char),
431 length == -1 ? need : MIN(length, need), stdin);
432 if (!n) {
433 if (ferror(stdin)) {
434 perror_msg("%s", _argv[-1]);
435 }
436 ateof = 1;
437 continue;
438 }
439 ateof = 0;
440 if (length != -1) {
441 length -= n;
442 }
443 if (!(need -= n)) {
444 if (vflag == ALL || vflag == FIRST ||
445 bcmp(curp, savp, blocksize)) {
446 if (vflag == DUP || vflag == FIRST) {
447 vflag = WAIT;
448 }
449 return(curp);
450 }
451 if (vflag == WAIT) {
452 printf("*\n");
453 }
454 vflag = DUP;
455 address = savaddress += blocksize;
456 need = blocksize;
457 nread = 0;
458 } else {
459 nread += n;
460 }
461 }
462}
463
464static void bpad(PR *pr)
465{
466 register char *p1, *p2;
467
468 /*
469 * remove all conversion flags; '-' is the only one valid
470 * with %s, and it's not useful here.
471 */
472 pr->flags = F_BPAD;
473 *pr->cchar = 's';
474 for (p1 = pr->fmt; *p1 != '%'; ++p1);
475 for (p2 = ++p1; *p1 && index(" -0+#", *p1); ++p1);
476 while ((*p2++ = *p1++) != 0) ;
477}
478
479void conv_c(PR *pr, u_char *p)
480{
481 char buf[10], *str;
482
483 switch(*p) {
484 case '\0':
485 str = "\\0";
486 goto strpr;
487 /* case '\a': */
488 case '\007':
489 str = "\\a";
490 goto strpr;
491 case '\b':
492 str = "\\b";
493 goto strpr;
494 case '\f':
495 str = "\\f";
496 goto strpr;
497 case '\n':
498 str = "\\n";
499 goto strpr;
500 case '\r':
501 str = "\\r";
502 goto strpr;
503 case '\t':
504 str = "\\t";
505 goto strpr;
506 case '\v':
507 str = "\\v";
508 goto strpr;
509 default:
510 break;
511 }
512 if (isprint(*p)) {
513 *pr->cchar = 'c';
514 (void)printf(pr->fmt, *p);
515 } else {
516 sprintf(str = buf, "%03o", (int)*p);
517strpr:
518 *pr->cchar = 's';
519 printf(pr->fmt, str);
520 }
521}
522
523void conv_u(PR *pr, u_char *p)
524{
525 static char *list[] = {
526 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
527 "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
528 "dle", "dcl", "dc2", "dc3", "dc4", "nak", "syn", "etb",
529 "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
530 };
531
532 /* od used nl, not lf */
533 if (*p <= 0x1f) {
534 *pr->cchar = 's';
535 printf(pr->fmt, list[*p]);
536 } else if (*p == 0x7f) {
537 *pr->cchar = 's';
538 printf(pr->fmt, "del");
539 } else if (isprint(*p)) {
540 *pr->cchar = 'c';
541 printf(pr->fmt, *p);
542 } else {
543 *pr->cchar = 'x';
544 printf(pr->fmt, (int)*p);
545 }
546}
547
548void display(void)
549{
550// extern FU *endfu;
551 register FS *fs;
552 register FU *fu;
553 register PR *pr;
554 register int cnt;
555 register u_char *bp;
556// off_t saveaddress;
557 u_char savech = 0, *savebp;
558
559 while ((bp = get()) != NULL) {
560 for (fs = fshead, savebp = bp, saveaddress = address; fs;
561 fs = fs->nextfs, bp = savebp, address = saveaddress) {
562 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
563 if (fu->flags & F_IGNORE) {
564 break;
565 }
566 for (cnt = fu->reps; cnt; --cnt) {
567 for (pr = fu->nextpr; pr; address += pr->bcnt,
568 bp += pr->bcnt, pr = pr->nextpr) {
569 if (eaddress && address >= eaddress &&
570 !(pr->flags&(F_TEXT|F_BPAD))) {
571 bpad(pr);
572 }
573 if (cnt == 1 && pr->nospace) {
574 savech = *pr->nospace;
575 *pr->nospace = '\0';
576 }
577// PRINT;
578 switch(pr->flags) {
579 case F_ADDRESS:
580 printf(pr->fmt, address);
581 break;
582 case F_BPAD:
583 printf(pr->fmt, "");
584 break;
585 case F_C:
586 conv_c(pr, bp);
587 break;
588 case F_CHAR:
589 printf(pr->fmt, *bp);
590 break;
591 case F_DBL: {
592 double dval;
593 float fval;
594 switch(pr->bcnt) {
595 case 4:
596 bcopy((char *)bp, (char *)&fval, sizeof(fval));
597 printf(pr->fmt, fval);
598 break;
599 case 8:
600 bcopy((char *)bp, (char *)&dval, sizeof(dval));
601 printf(pr->fmt, dval);
602 break;
603 }
604 break;
605 }
606 case F_INT: {
607 int ival;
608 short sval;
609 switch(pr->bcnt) {
610 case 1:
611 printf(pr->fmt, (int)*bp);
612 break;
613 case 2:
614 bcopy((char *)bp, (char *)&sval, sizeof(sval));
615 printf(pr->fmt, (int)sval);
616 break;
617 case 4:
618 bcopy((char *)bp, (char *)&ival, sizeof(ival));
619 printf(pr->fmt, ival);
620 break;
621 }
622 break;
623 }
624 case F_P:
625 printf(pr->fmt, isprint(*bp) ? *bp : '.');
626 break;
627 case F_STR:
628 printf(pr->fmt, (char *)bp);
629 break;
630 case F_TEXT:
631 printf(pr->fmt);
632 break;
633 case F_U:
634 conv_u(pr, bp);
635 break;
636 case F_UINT: {
637 u_int ival;
638 u_short sval;
639 switch(pr->bcnt) {
640 case 1:
641 printf(pr->fmt, (u_int)*bp);
642 break;
643 case 2:
644 bcopy((char *)bp, (char *)&sval, sizeof(sval));
645 printf(pr->fmt, (u_int)sval);
646 break;
647 case 4:
648 bcopy((char *)bp, (char *)&ival, sizeof(ival));
649 printf(pr->fmt, ival);
650 break;
651 }
652 break;
653 }
654 }
655 if (cnt == 1 && pr->nospace) {
656 *pr->nospace = savech;
657 }
658 }
659 }
660 }
661 }
662 }
663 if (endfu) {
664 /*
665 * if eaddress not set, error or file size was multiple of
666 * blocksize, and no partial block ever found.
667 */
668 if (!eaddress) {
669 if (!address) {
670 return;
671 }
672 eaddress = address;
673 }
674 for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
675 switch(pr->flags) {
676 case F_ADDRESS:
677 (void)printf(pr->fmt, eaddress);
678 break;
679 case F_TEXT:
680 (void)printf(pr->fmt);
681 break;
682 }
683 }
684 }
685}
686
687int dump(char **argv)
688{
689 register FS *tfs;
690
691 /* figure out the data block size */
692 for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
693 tfs->bcnt = size(tfs);
694 if (blocksize < tfs->bcnt) {
695 blocksize = tfs->bcnt;
696 }
697 }
698 /* rewrite the rules, do syntax checking */
699 for (tfs = fshead; tfs; tfs = tfs->nextfs) {
700 rewrite(tfs);
701 }
702
703 next(argv);
704 display();
705
706 return(exitval);
707}
708
709void add(char *fmt)
710{
711 register char *p;
712 register char *p1;
713 register char *p2;
714 static FS **nextfs;
715 FS *tfs;
716 FU *tfu, **nextfu;
717 char *savep;
718
719 /* start new linked list of format units */
720 /* NOSTRICT */
721 tfs = (FS *)xmalloc(sizeof(FS));
722 if (!fshead) {
723 fshead = tfs;
724 } else {
725 *nextfs = tfs;
726 }
727 nextfs = &tfs->nextfs;
728 nextfu = &tfs->nextfu;
729
730 /* take the format string and break it up into format units */
731 for (p = fmt;;) {
732 /* skip leading white space */
733 for (; isspace(*p); ++p);
734 if (!*p) {
735 break;
736 }
737
738 /* allocate a new format unit and link it in */
739 /* NOSTRICT */
740 tfu = (FU *)xmalloc(sizeof(FU));
741 *nextfu = tfu;
742 nextfu = &tfu->nextfu;
743 tfu->reps = 1;
744
745 /* if leading digit, repetition count */
746 if (isdigit(*p)) {
747 for (savep = p; isdigit(*p); ++p);
748 if (!isspace(*p) && *p != '/') {
749 error_msg_and_die("hexdump: bad format {%s}", fmt);
750 }
751 /* may overwrite either white space or slash */
752 tfu->reps = atoi(savep);
753 tfu->flags = F_SETREP;
754 /* skip trailing white space */
755 for (++p; isspace(*p); ++p);
756 }
757
758 /* skip slash and trailing white space */
759 if (*p == '/') {
760 while (isspace(*++p));
761 }
762
763 /* byte count */
764 if (isdigit(*p)) {
765 for (savep = p; isdigit(*p); ++p);
766 if (!isspace(*p)) {
767 error_msg_and_die("hexdump: bad format {%s}", fmt);
768 }
769 tfu->bcnt = atoi(savep);
770 /* skip trailing white space */
771 for (++p; isspace(*p); ++p);
772 }
773
774 /* format */
775 if (*p != '"') {
776 error_msg_and_die("hexdump: bad format {%s}", fmt);
777 }
778 for (savep = ++p; *p != '"';) {
779 if (*p++ == 0) {
780 error_msg_and_die("hexdump: bad format {%s}", fmt);
781 }
782 }
783 if (!(tfu->fmt = malloc(p - savep + 1))) {
784 perror_msg_and_die("hexdump");
785 }
786 strncpy(tfu->fmt, savep, p - savep);
787 tfu->fmt[p - savep] = '\0';
788// escape(tfu->fmt);
789
790 p1 = tfu->fmt;
791
792 /* alphabetic escape sequences have to be done in place */
793 for (p2 = p1;; ++p1, ++p2) {
794 if (!*p1) {
795 *p2 = *p1;
796 break;
797 }
798 if (*p1 == '\\') {
799 switch(*++p1) {
800 case 'a':
801 /* *p2 = '\a'; */
802 *p2 = '\007';
803 break;
804 case 'b':
805 *p2 = '\b';
806 break;
807 case 'f':
808 *p2 = '\f';
809 break;
810 case 'n':
811 *p2 = '\n';
812 break;
813 case 'r':
814 *p2 = '\r';
815 break;
816 case 't':
817 *p2 = '\t';
818 break;
819 case 'v':
820 *p2 = '\v';
821 break;
822 default:
823 *p2 = *p1;
824 break;
825 }
826 }
827 }
828
829 p++;
830 }
831}
832/*
833 * Copyright (c) 1989 The Regents of the University of California.
834 * All rights reserved.
835 *
836 * Redistribution and use in source and binary forms, with or without
837 * modification, are permitted provided that the following conditions
838 * are met:
839 * 1. Redistributions of source code must retain the above copyright
840 * notice, this list of conditions and the following disclaimer.
841 * 2. Redistributions in binary form must reproduce the above copyright
842 * notice, this list of conditions and the following disclaimer in the
843 * documentation and/or other materials provided with the distribution.
844 * 3. All advertising materials mentioning features or use of this software
845 * must display the following acknowledgement:
846 * This product includes software developed by the University of
847 * California, Berkeley and its contributors.
848 * 4. Neither the name of the University nor the names of its contributors
849 * may be used to endorse or promote products derived from this software
850 * without specific prior written permission.
851 *
852 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
853 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
854 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
855 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
856 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
857 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
858 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
859 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
860 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
861 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
862 * SUCH DAMAGE.
863 */