aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-09-24 18:24:17 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-09-24 18:24:17 +0000
commit47ddd01b3cc8d262f6c97b41b4bb480281eeb591 (patch)
tree4794e2f04874d002378776282bb43c164083d9ba
parent7710563858a1e1d1a0af81d18222eee0259c00f2 (diff)
downloadbusybox-w32-47ddd01b3cc8d262f6c97b41b4bb480281eeb591.tar.gz
busybox-w32-47ddd01b3cc8d262f6c97b41b4bb480281eeb591.tar.bz2
busybox-w32-47ddd01b3cc8d262f6c97b41b4bb480281eeb591.zip
wget: reorder functions, no code changes
-rw-r--r--networking/wget.c621
1 files changed, 305 insertions, 316 deletions
diff --git a/networking/wget.c b/networking/wget.c
index 2cc426f19..23a2fa855 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -50,20 +50,166 @@ struct BUG_G_too_big {
50#define INIT_G() do { } while (0) 50#define INIT_G() do { } while (0)
51 51
52 52
53static void parse_url(char *url, struct host_info *h);
54static FILE *open_socket(len_and_sockaddr *lsa);
55static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*,int *istrunc*/ );
56static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf);
57
58#if ENABLE_FEATURE_WGET_STATUSBAR 53#if ENABLE_FEATURE_WGET_STATUSBAR
59static void progressmeter(int flag);
60enum { 54enum {
61 STALLTIME = 5 /* Seconds when xfer considered "stalled" */ 55 STALLTIME = 5 /* Seconds when xfer considered "stalled" */
62}; 56};
63#else 57
64static ALWAYS_INLINE void progressmeter(int flag) {} 58static int getttywidth(void)
59{
60 int width;
61 get_terminal_width_height(0, &width, NULL);
62 return width;
63}
64
65static void updateprogressmeter(int ignore)
66{
67 int save_errno = errno;
68
69 progressmeter(0);
70 errno = save_errno;
71}
72
73static void alarmtimer(int iwait)
74{
75 struct itimerval itv;
76
77 itv.it_value.tv_sec = iwait;
78 itv.it_value.tv_usec = 0;
79 itv.it_interval = itv.it_value;
80 setitimer(ITIMER_REAL, &itv, NULL);
81}
82
83static void progressmeter(int flag)
84{
85 off_t abbrevsize;
86 unsigned since_last_update, elapsed;
87 unsigned ratio;
88 int barlength, i;
89
90 if (flag == -1) { /* first call to progressmeter */
91 start_sec = monotonic_sec();
92 lastupdate_sec = start_sec;
93 lastsize = 0;
94 totalsize = content_len + beg_range; /* as content_len changes.. */
95 }
96
97 ratio = 100;
98 if (totalsize != 0 && !chunked) {
99 /* long long helps to have it working even if !LFS */
100 ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize);
101 if (ratio > 100) ratio = 100;
102 }
103
104 fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
105
106 barlength = getttywidth() - 49;
107 if (barlength > 0) {
108 /* god bless gcc for variable arrays :) */
109 i = barlength * ratio / 100;
110 {
111 char buf[i+1];
112 memset(buf, '*', i);
113 buf[i] = '\0';
114 fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
115 }
116 }
117 i = 0;
118 abbrevsize = transferred + beg_range;
119 while (abbrevsize >= 100000) {
120 i++;
121 abbrevsize >>= 10;
122 }
123 /* see http://en.wikipedia.org/wiki/Tera */
124 fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]);
125
126// Nuts! Ain't it easier to update progress meter ONLY when we transferred++?
127// FIXME: get rid of alarmtimer + updateprogressmeter mess
128
129 elapsed = monotonic_sec();
130 since_last_update = elapsed - lastupdate_sec;
131 if (transferred > lastsize) {
132 lastupdate_sec = elapsed;
133 lastsize = transferred;
134 if (since_last_update >= STALLTIME) {
135 /* We "cut off" these seconds from elapsed time
136 * by adjusting start time */
137 start_sec += since_last_update;
138 }
139 since_last_update = 0; /* we are un-stalled now */
140 }
141 elapsed -= start_sec; /* now it's "elapsed since start" */
142
143 if (since_last_update >= STALLTIME) {
144 fprintf(stderr, " - stalled -");
145 } else {
146 off_t to_download = totalsize - beg_range;
147 if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) {
148 fprintf(stderr, "--:--:-- ETA");
149 } else {
150 /* to_download / (transferred/elapsed) - elapsed: */
151 int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed);
152 /* (long long helps to have working ETA even if !LFS) */
153 i = eta % 3600;
154 fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
155 }
156 }
157
158 if (flag == -1) { /* first call to progressmeter */
159 struct sigaction sa;
160 sa.sa_handler = updateprogressmeter;
161 sigemptyset(&sa.sa_mask);
162 sa.sa_flags = SA_RESTART;
163 sigaction(SIGALRM, &sa, NULL);
164 alarmtimer(1);
165 } else if (flag == 1) { /* last call to progressmeter */
166 alarmtimer(0);
167 transferred = 0;
168 putc('\n', stderr);
169 }
170}
171/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
172 * much of which was blatantly stolen from openssh. */
173/*-
174 * Copyright (c) 1992, 1993
175 * The Regents of the University of California. All rights reserved.
176 *
177 * Redistribution and use in source and binary forms, with or without
178 * modification, are permitted provided that the following conditions
179 * are met:
180 * 1. Redistributions of source code must retain the above copyright
181 * notice, this list of conditions and the following disclaimer.
182 * 2. Redistributions in binary form must reproduce the above copyright
183 * notice, this list of conditions and the following disclaimer in the
184 * documentation and/or other materials provided with the distribution.
185 *
186 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
187 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
188 *
189 * 4. Neither the name of the University nor the names of its contributors
190 * may be used to endorse or promote products derived from this software
191 * without specific prior written permission.
192 *
193 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
194 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
195 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
196 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
197 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
200 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
201 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
202 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
203 * SUCH DAMAGE.
204 *
205 */
206#else /* FEATURE_WGET_STATUSBAR */
207
208static ALWAYS_INLINE void progressmeter(int flag) { }
209
65#endif 210#endif
66 211
212
67/* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, 213/* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read,
68 * and a short count if an eof or non-interrupt error is encountered. */ 214 * and a short count if an eof or non-interrupt error is encountered. */
69static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) 215static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream)
@@ -107,6 +253,157 @@ static char *base64enc_512(char buf[512], const char *str)
107} 253}
108#endif 254#endif
109 255
256
257static FILE *open_socket(len_and_sockaddr *lsa)
258{
259 FILE *fp;
260
261 /* glibc 2.4 seems to try seeking on it - ??! */
262 /* hopefully it understands what ESPIPE means... */
263 fp = fdopen(xconnect_stream(lsa), "r+");
264 if (fp == NULL)
265 bb_perror_msg_and_die("fdopen");
266
267 return fp;
268}
269
270
271static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
272{
273 int result;
274 if (s1) {
275 if (!s2) s2 = "";
276 fprintf(fp, "%s%s\r\n", s1, s2);
277 fflush(fp);
278 }
279
280 do {
281 char *buf_ptr;
282
283 if (fgets(buf, 510, fp) == NULL) {
284 bb_perror_msg_and_die("error getting response");
285 }
286 buf_ptr = strstr(buf, "\r\n");
287 if (buf_ptr) {
288 *buf_ptr = '\0';
289 }
290 } while (!isdigit(buf[0]) || buf[3] != ' ');
291
292 buf[3] = '\0';
293 result = xatoi_u(buf);
294 buf[3] = ' ';
295 return result;
296}
297
298
299static void parse_url(char *src_url, struct host_info *h)
300{
301 char *url, *p, *sp;
302
303 /* h->allocated = */ url = xstrdup(src_url);
304
305 if (strncmp(url, "http://", 7) == 0) {
306 h->port = bb_lookup_port("http", "tcp", 80);
307 h->host = url + 7;
308 h->is_ftp = 0;
309 } else if (strncmp(url, "ftp://", 6) == 0) {
310 h->port = bb_lookup_port("ftp", "tcp", 21);
311 h->host = url + 6;
312 h->is_ftp = 1;
313 } else
314 bb_error_msg_and_die("not an http or ftp url: %s", url);
315
316 // FYI:
317 // "Real" wget 'http://busybox.net?var=a/b' sends this request:
318 // 'GET /?var=a/b HTTP 1.0'
319 // and saves 'index.html?var=a%2Fb' (we save 'b')
320 // wget 'http://busybox.net?login=john@doe':
321 // request: 'GET /?login=john@doe HTTP/1.0'
322 // saves: 'index.html?login=john@doe' (we save '?login=john@doe')
323 // wget 'http://busybox.net#test/test':
324 // request: 'GET / HTTP/1.0'
325 // saves: 'index.html' (we save 'test')
326 //
327 // We also don't add unique .N suffix if file exists...
328 sp = strchr(h->host, '/');
329 p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p;
330 p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p;
331 if (!sp) {
332 /* must be writable because of bb_get_last_path_component() */
333 static char nullstr[] ALIGN1 = "";
334 h->path = nullstr;
335 } else if (*sp == '/') {
336 *sp = '\0';
337 h->path = sp + 1;
338 } else { // '#' or '?'
339 // http://busybox.net?login=john@doe is a valid URL
340 // memmove converts to:
341 // http:/busybox.nett?login=john@doe...
342 memmove(h->host-1, h->host, sp - h->host);
343 h->host--;
344 sp[-1] = '\0';
345 h->path = sp;
346 }
347
348 sp = strrchr(h->host, '@');
349 h->user = NULL;
350 if (sp != NULL) {
351 h->user = h->host;
352 *sp = '\0';
353 h->host = sp + 1;
354 }
355
356 sp = h->host;
357}
358
359
360static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
361{
362 char *s, *hdrval;
363 int c;
364
365 /* *istrunc = 0; */
366
367 /* retrieve header line */
368 if (fgets(buf, bufsiz, fp) == NULL)
369 return NULL;
370
371 /* see if we are at the end of the headers */
372 for (s = buf; *s == '\r'; ++s)
373 continue;
374 if (*s == '\n')
375 return NULL;
376
377 /* convert the header name to lower case */
378 for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s)
379 *s = tolower(*s);
380
381 /* verify we are at the end of the header name */
382 if (*s != ':')
383 bb_error_msg_and_die("bad header line: %s", buf);
384
385 /* locate the start of the header value */
386 *s++ = '\0';
387 hdrval = skip_whitespace(s);
388
389 /* locate the end of header */
390 while (*s && *s != '\r' && *s != '\n')
391 ++s;
392
393 /* end of header found */
394 if (*s) {
395 *s = '\0';
396 return hdrval;
397 }
398
399 /* Rats! The buffer isn't big enough to hold the entire header value. */
400 while (c = getc(fp), c != EOF && c != '\n')
401 continue;
402 /* *istrunc = 1; */
403 return hdrval;
404}
405
406
110int wget_main(int argc, char **argv); 407int wget_main(int argc, char **argv);
111int wget_main(int argc, char **argv) 408int wget_main(int argc, char **argv)
112{ 409{
@@ -527,312 +824,4 @@ int wget_main(int argc, char **argv)
527 } 824 }
528 825
529 return EXIT_SUCCESS; 826 return EXIT_SUCCESS;
530} /* wget_main() */
531
532
533static void parse_url(char *src_url, struct host_info *h)
534{
535 char *url, *p, *sp;
536
537 /* h->allocated = */ url = xstrdup(src_url);
538
539 if (strncmp(url, "http://", 7) == 0) {
540 h->port = bb_lookup_port("http", "tcp", 80);
541 h->host = url + 7;
542 h->is_ftp = 0;
543 } else if (strncmp(url, "ftp://", 6) == 0) {
544 h->port = bb_lookup_port("ftp", "tcp", 21);
545 h->host = url + 6;
546 h->is_ftp = 1;
547 } else
548 bb_error_msg_and_die("not an http or ftp url: %s", url);
549
550 // FYI:
551 // "Real" wget 'http://busybox.net?var=a/b' sends this request:
552 // 'GET /?var=a/b HTTP 1.0'
553 // and saves 'index.html?var=a%2Fb' (we save 'b')
554 // wget 'http://busybox.net?login=john@doe':
555 // request: 'GET /?login=john@doe HTTP/1.0'
556 // saves: 'index.html?login=john@doe' (we save '?login=john@doe')
557 // wget 'http://busybox.net#test/test':
558 // request: 'GET / HTTP/1.0'
559 // saves: 'index.html' (we save 'test')
560 //
561 // We also don't add unique .N suffix if file exists...
562 sp = strchr(h->host, '/');
563 p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p;
564 p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p;
565 if (!sp) {
566 /* must be writable because of bb_get_last_path_component() */
567 static char nullstr[] ALIGN1 = "";
568 h->path = nullstr;
569 } else if (*sp == '/') {
570 *sp = '\0';
571 h->path = sp + 1;
572 } else { // '#' or '?'
573 // http://busybox.net?login=john@doe is a valid URL
574 // memmove converts to:
575 // http:/busybox.nett?login=john@doe...
576 memmove(h->host-1, h->host, sp - h->host);
577 h->host--;
578 sp[-1] = '\0';
579 h->path = sp;
580 }
581
582 sp = strrchr(h->host, '@');
583 h->user = NULL;
584 if (sp != NULL) {
585 h->user = h->host;
586 *sp = '\0';
587 h->host = sp + 1;
588 }
589
590 sp = h->host;
591}
592
593
594static FILE *open_socket(len_and_sockaddr *lsa)
595{
596 FILE *fp;
597
598 /* glibc 2.4 seems to try seeking on it - ??! */
599 /* hopefully it understands what ESPIPE means... */
600 fp = fdopen(xconnect_stream(lsa), "r+");
601 if (fp == NULL)
602 bb_perror_msg_and_die("fdopen");
603
604 return fp;
605} 827}
606
607
608static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/)
609{
610 char *s, *hdrval;
611 int c;
612
613 /* *istrunc = 0; */
614
615 /* retrieve header line */
616 if (fgets(buf, bufsiz, fp) == NULL)
617 return NULL;
618
619 /* see if we are at the end of the headers */
620 for (s = buf; *s == '\r'; ++s)
621 continue;
622 if (*s == '\n')
623 return NULL;
624
625 /* convert the header name to lower case */
626 for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s)
627 *s = tolower(*s);
628
629 /* verify we are at the end of the header name */
630 if (*s != ':')
631 bb_error_msg_and_die("bad header line: %s", buf);
632
633 /* locate the start of the header value */
634 *s++ = '\0';
635 hdrval = skip_whitespace(s);
636
637 /* locate the end of header */
638 while (*s && *s != '\r' && *s != '\n')
639 ++s;
640
641 /* end of header found */
642 if (*s) {
643 *s = '\0';
644 return hdrval;
645 }
646
647 /* Rats! The buffer isn't big enough to hold the entire header value. */
648 while (c = getc(fp), c != EOF && c != '\n')
649 continue;
650 /* *istrunc = 1; */
651 return hdrval;
652}
653
654static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf)
655{
656 int result;
657 if (s1) {
658 if (!s2) s2 = "";
659 fprintf(fp, "%s%s\r\n", s1, s2);
660 fflush(fp);
661 }
662
663 do {
664 char *buf_ptr;
665
666 if (fgets(buf, 510, fp) == NULL) {
667 bb_perror_msg_and_die("error getting response");
668 }
669 buf_ptr = strstr(buf, "\r\n");
670 if (buf_ptr) {
671 *buf_ptr = '\0';
672 }
673 } while (!isdigit(buf[0]) || buf[3] != ' ');
674
675 buf[3] = '\0';
676 result = xatoi_u(buf);
677 buf[3] = ' ';
678 return result;
679}
680
681#if ENABLE_FEATURE_WGET_STATUSBAR
682/* Stuff below is from BSD rcp util.c, as added to openshh.
683 * Original copyright notice is retained at the end of this file.
684 */
685static int
686getttywidth(void)
687{
688 int width;
689 get_terminal_width_height(0, &width, NULL);
690 return width;
691}
692
693static void
694updateprogressmeter(int ignore)
695{
696 int save_errno = errno;
697
698 progressmeter(0);
699 errno = save_errno;
700}
701
702static void alarmtimer(int iwait)
703{
704 struct itimerval itv;
705
706 itv.it_value.tv_sec = iwait;
707 itv.it_value.tv_usec = 0;
708 itv.it_interval = itv.it_value;
709 setitimer(ITIMER_REAL, &itv, NULL);
710}
711
712static void
713progressmeter(int flag)
714{
715 off_t abbrevsize;
716 unsigned since_last_update, elapsed;
717 unsigned ratio;
718 int barlength, i;
719
720 if (flag == -1) { /* first call to progressmeter */
721 start_sec = monotonic_sec();
722 lastupdate_sec = start_sec;
723 lastsize = 0;
724 totalsize = content_len + beg_range; /* as content_len changes.. */
725 }
726
727 ratio = 100;
728 if (totalsize != 0 && !chunked) {
729 /* long long helps to have it working even if !LFS */
730 ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize);
731 if (ratio > 100) ratio = 100;
732 }
733
734 fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
735
736 barlength = getttywidth() - 49;
737 if (barlength > 0) {
738 /* god bless gcc for variable arrays :) */
739 i = barlength * ratio / 100;
740 {
741 char buf[i+1];
742 memset(buf, '*', i);
743 buf[i] = '\0';
744 fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
745 }
746 }
747 i = 0;
748 abbrevsize = transferred + beg_range;
749 while (abbrevsize >= 100000) {
750 i++;
751 abbrevsize >>= 10;
752 }
753 /* see http://en.wikipedia.org/wiki/Tera */
754 fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]);
755
756// Nuts! Ain't it easier to update progress meter ONLY when we transferred++?
757// FIXME: get rid of alarmtimer + updateprogressmeter mess
758
759 elapsed = monotonic_sec();
760 since_last_update = elapsed - lastupdate_sec;
761 if (transferred > lastsize) {
762 lastupdate_sec = elapsed;
763 lastsize = transferred;
764 if (since_last_update >= STALLTIME) {
765 /* We "cut off" these seconds from elapsed time
766 * by adjusting start time */
767 start_sec += since_last_update;
768 }
769 since_last_update = 0; /* we are un-stalled now */
770 }
771 elapsed -= start_sec; /* now it's "elapsed since start" */
772
773 if (since_last_update >= STALLTIME) {
774 fprintf(stderr, " - stalled -");
775 } else {
776 off_t to_download = totalsize - beg_range;
777 if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || chunked) {
778 fprintf(stderr, "--:--:-- ETA");
779 } else {
780 /* to_download / (transferred/elapsed) - elapsed: */
781 int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed);
782 /* (long long helps to have working ETA even if !LFS) */
783 i = eta % 3600;
784 fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
785 }
786 }
787
788 if (flag == -1) { /* first call to progressmeter */
789 struct sigaction sa;
790 sa.sa_handler = updateprogressmeter;
791 sigemptyset(&sa.sa_mask);
792 sa.sa_flags = SA_RESTART;
793 sigaction(SIGALRM, &sa, NULL);
794 alarmtimer(1);
795 } else if (flag == 1) { /* last call to progressmeter */
796 alarmtimer(0);
797 transferred = 0;
798 putc('\n', stderr);
799 }
800}
801#endif /* FEATURE_WGET_STATUSBAR */
802
803/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
804 * much of which was blatantly stolen from openssh. */
805
806/*-
807 * Copyright (c) 1992, 1993
808 * The Regents of the University of California. All rights reserved.
809 *
810 * Redistribution and use in source and binary forms, with or without
811 * modification, are permitted provided that the following conditions
812 * are met:
813 * 1. Redistributions of source code must retain the above copyright
814 * notice, this list of conditions and the following disclaimer.
815 * 2. Redistributions in binary form must reproduce the above copyright
816 * notice, this list of conditions and the following disclaimer in the
817 * documentation and/or other materials provided with the distribution.
818 *
819 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
820 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
821 *
822 * 4. Neither the name of the University nor the names of its contributors
823 * may be used to endorse or promote products derived from this software
824 * without specific prior written permission.
825 *
826 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
827 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
828 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
829 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
830 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
831 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
832 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
833 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
834 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
835 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
836 * SUCH DAMAGE.
837 *
838 */