]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/awk/lib.c
python: update python build configuration to new ape capabilities like getaddrinfo...
[plan9front.git] / sys / src / cmd / awk / lib.c
1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
4
5 Permission to use, copy, modify, and distribute this software and
6 its documentation for any purpose and without fee is hereby
7 granted, provided that the above copyright notice appear in all
8 copies and that both that the copyright notice and this
9 permission notice and warranty disclaimer appear in supporting
10 documentation, and that the name Lucent Technologies or any of
11 its entities not be used in advertising or publicity pertaining
12 to distribution of the software without specific, written prior
13 permission.
14
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 THIS SOFTWARE.
23 ****************************************************************/
24
25 #define DEBUG
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include "awk.h"
33 #include "y.tab.h"
34
35 FILE    *infile = NULL;
36 char    *file   = "";
37 char    *record;
38 int     recsize = RECSIZE;
39 char    *fields;
40 int     fieldssize = RECSIZE;
41
42 Cell    **fldtab;       /* pointers to Cells */
43 char    inputFS[100] = " ";
44
45 #define MAXFLD  200
46 int     nfields = MAXFLD;       /* last allocated slot for $i */
47
48 int     donefld;        /* 1 = implies rec broken into fields */
49 int     donerec;        /* 1 = record is valid (no flds have changed) */
50
51 int     lastfld = 0;    /* last used field */
52 int     argno   = 1;    /* current input argument number */
53 extern  Awkfloat *ARGC;
54
55 static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
56 static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
57
58 void recinit(unsigned int n)
59 {
60         record = (char *) malloc(n);
61         fields = (char *) malloc(n);
62         fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
63         if (record == NULL || fields == NULL || fldtab == NULL)
64                 FATAL("out of space for $0 and fields");
65         fldtab[0] = (Cell *) malloc(sizeof (Cell));
66         *fldtab[0] = dollar0;
67         fldtab[0]->sval = record;
68         fldtab[0]->nval = tostring("0");
69         makefields(1, nfields);
70 }
71
72 void makefields(int n1, int n2)         /* create $n1..$n2 inclusive */
73 {
74         char temp[50];
75         int i;
76
77         for (i = n1; i <= n2; i++) {
78                 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
79                 if (fldtab[i] == NULL)
80                         FATAL("out of space in makefields %d", i);
81                 *fldtab[i] = dollar1;
82                 sprintf(temp, "%d", i);
83                 fldtab[i]->nval = tostring(temp);
84         }
85 }
86
87 void initgetrec(void)
88 {
89         int i;
90         char *p;
91
92         for (i = 1; i < *ARGC; i++) {
93                 if (!isclvar(p = getargv(i))) { /* find 1st real filename */
94                         setsval(lookup("FILENAME", symtab), getargv(i));
95                         return;
96                 }
97                 setclvar(p);    /* a commandline assignment before filename */
98                 argno++;
99         }
100         infile = stdin;         /* no filenames, so use stdin */
101 }
102
103 int getrec(char **pbuf, int *pbufsize, int isrecord)    /* get next input record */
104 {                       /* note: cares whether buf == record */
105         int c;
106         static int firsttime = 1;
107         char *buf = *pbuf;
108         int bufsize = *pbufsize;
109
110         if (firsttime) {
111                 firsttime = 0;
112                 initgetrec();
113         }
114            dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
115                 *RS, *FS, *ARGC, *FILENAME) );
116         if (isrecord) {
117                 donefld = 0;
118                 donerec = 1;
119         }
120         buf[0] = 0;
121         while (argno < *ARGC || infile == stdin) {
122                    dprintf( ("argno=%d, file=|%s|\n", argno, file) );
123                 if (infile == NULL) {   /* have to open a new file */
124                         file = getargv(argno);
125                         if (*file == '\0') {    /* it's been zapped */
126                                 argno++;
127                                 continue;
128                         }
129                         if (isclvar(file)) {    /* a var=value arg */
130                                 setclvar(file);
131                                 argno++;
132                                 continue;
133                         }
134                         *FILENAME = file;
135                            dprintf( ("opening file %s\n", file) );
136                         if (*file == '-' && *(file+1) == '\0')
137                                 infile = stdin;
138                         else if ((infile = fopen(file, "r")) == NULL)
139                                 FATAL("can't open file %s", file);
140                         setfval(fnrloc, 0.0);
141                 }
142                 c = readrec(&buf, &bufsize, infile);
143                 if (c != 0 || buf[0] != '\0') { /* normal record */
144                         if (isrecord) {
145                                 if (freeable(fldtab[0]))
146                                         xfree(fldtab[0]->sval);
147                                 fldtab[0]->sval = buf;  /* buf == record */
148                                 fldtab[0]->tval = REC | STR | DONTFREE;
149                                 if (is_number(fldtab[0]->sval)) {
150                                         fldtab[0]->fval = atof(fldtab[0]->sval);
151                                         fldtab[0]->tval |= NUM;
152                                 }
153                         }
154                         setfval(nrloc, nrloc->fval+1);
155                         setfval(fnrloc, fnrloc->fval+1);
156                         *pbuf = buf;
157                         *pbufsize = bufsize;
158                         return 1;
159                 }
160                 /* EOF arrived on this file; set up next */
161                 if (infile != stdin)
162                         fclose(infile);
163                 infile = NULL;
164                 argno++;
165         }
166         *pbuf = buf;
167         *pbufsize = bufsize;
168         return 0;       /* true end of file */
169 }
170
171 void nextfile(void)
172 {
173         if (infile != stdin)
174                 fclose(infile);
175         infile = NULL;
176         argno++;
177 }
178
179 int readrec(char **pbuf, int *pbufsize, FILE *inf)      /* read one record into buf */
180 {
181         int sep, c;
182         char *rr, *buf = *pbuf;
183         int bufsize = *pbufsize;
184
185         if (strlen(*FS) >= sizeof(inputFS))
186                 FATAL("field separator %.10s... is too long", *FS);
187         strcpy(inputFS, *FS);   /* for subsequent field splitting */
188         if ((sep = **RS) == 0) {
189                 sep = '\n';
190                 while ((c=getc(inf)) == '\n' && c != EOF)       /* skip leading \n's */
191                         ;
192                 if (c != EOF)
193                         ungetc(c, inf);
194         }
195         for (rr = buf; ; ) {
196                 for (; (c=getc(inf)) != sep && c != EOF; ) {
197                         if (rr-buf+1 > bufsize)
198                                 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
199                                         FATAL("input record `%.30s...' too long", buf);
200                         *rr++ = c;
201                 }
202                 if (**RS == sep || c == EOF)
203                         break;
204                 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
205                         break;
206                 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
207                         FATAL("input record `%.30s...' too long", buf);
208                 *rr++ = '\n';
209                 *rr++ = c;
210         }
211         if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
212                 FATAL("input record `%.30s...' too long", buf);
213         *rr = 0;
214            dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
215         *pbuf = buf;
216         *pbufsize = bufsize;
217         return c == EOF && rr == buf ? 0 : 1;
218 }
219
220 char *getargv(int n)    /* get ARGV[n] */
221 {
222         Cell *x;
223         char *s, temp[50];
224         extern Array *ARGVtab;
225
226         sprintf(temp, "%d", n);
227         x = setsymtab(temp, "", 0.0, STR, ARGVtab);
228         s = getsval(x);
229            dprintf( ("getargv(%d) returns |%s|\n", n, s) );
230         return s;
231 }
232
233 void setclvar(char *s)  /* set var=value from s */
234 {
235         char *p;
236         Cell *q;
237
238         for (p=s; *p != '='; p++)
239                 ;
240         *p++ = 0;
241         p = qstring(p, '\0');
242         q = setsymtab(s, p, 0.0, STR, symtab);
243         setsval(q, p);
244         if (is_number(q->sval)) {
245                 q->fval = atof(q->sval);
246                 q->tval |= NUM;
247         }
248            dprintf( ("command line set %s to |%s|\n", s, p) );
249 }
250
251
252 void fldbld(void)       /* create fields from current record */
253 {
254         /* this relies on having fields[] the same length as $0 */
255         /* the fields are all stored in this one array with \0's */
256         char *r, *fr, sep;
257         Cell *p;
258         int i, j, n;
259
260         if (donefld)
261                 return;
262         if (!isstr(fldtab[0]))
263                 getsval(fldtab[0]);
264         r = fldtab[0]->sval;
265         n = strlen(r);
266         if (n > fieldssize) {
267                 xfree(fields);
268                 if ((fields = (char *) malloc(n+1)) == NULL)
269                         FATAL("out of space for fields in fldbld %d", n);
270                 fieldssize = n;
271         }
272         fr = fields;
273         i = 0;  /* number of fields accumulated here */
274         if (strlen(inputFS) > 1) {      /* it's a regular expression */
275                 i = refldbld(r, inputFS);
276         } else if ((sep = *inputFS) == ' ') {   /* default whitespace */
277                 for (i = 0; ; ) {
278                         while (*r == ' ' || *r == '\t' || *r == '\n')
279                                 r++;
280                         if (*r == 0)
281                                 break;
282                         i++;
283                         if (i > nfields)
284                                 growfldtab(i);
285                         if (freeable(fldtab[i]))
286                                 xfree(fldtab[i]->sval);
287                         fldtab[i]->sval = fr;
288                         fldtab[i]->tval = FLD | STR | DONTFREE;
289                         do
290                                 *fr++ = *r++;
291                         while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
292                         *fr++ = 0;
293                 }
294                 *fr = 0;
295         } else if ((sep = *inputFS) == 0) {             /* new: FS="" => 1 char/field */
296                 for (i = 0; *r != 0; r++) {
297                         char buf[2];
298                         i++;
299                         if (i > nfields)
300                                 growfldtab(i);
301                         if (freeable(fldtab[i]))
302                                 xfree(fldtab[i]->sval);
303                         buf[0] = *r;
304                         buf[1] = 0;
305                         fldtab[i]->sval = tostring(buf);
306                         fldtab[i]->tval = FLD | STR;
307                 }
308                 *fr = 0;
309         } else if (*r != 0) {   /* if 0, it's a null field */
310                 for (;;) {
311                         i++;
312                         if (i > nfields)
313                                 growfldtab(i);
314                         if (freeable(fldtab[i]))
315                                 xfree(fldtab[i]->sval);
316                         fldtab[i]->sval = fr;
317                         fldtab[i]->tval = FLD | STR | DONTFREE;
318                         while (*r != sep && *r != '\n' && *r != '\0')   /* \n is always a separator */
319                                 *fr++ = *r++;
320                         *fr++ = 0;
321                         if (*r++ == 0)
322                                 break;
323                 }
324                 *fr = 0;
325         }
326         if (i > nfields)
327                 FATAL("record `%.30s...' has too many fields; can't happen", r);
328         cleanfld(i+1, lastfld); /* clean out junk from previous record */
329         lastfld = i;
330         donefld = 1;
331         for (j = 1; j <= lastfld; j++) {
332                 p = fldtab[j];
333                 if(is_number(p->sval)) {
334                         p->fval = atof(p->sval);
335                         p->tval |= NUM;
336                 }
337         }
338         setfval(nfloc, (Awkfloat) lastfld);
339         if (dbg) {
340                 for (j = 0; j <= lastfld; j++) {
341                         p = fldtab[j];
342                         printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
343                 }
344         }
345 }
346
347 void cleanfld(int n1, int n2)   /* clean out fields n1 .. n2 inclusive */
348 {                               /* nvals remain intact */
349         Cell *p;
350         int i;
351
352         for (i = n1; i <= n2; i++) {
353                 p = fldtab[i];
354                 if (freeable(p))
355                         xfree(p->sval);
356                 p->sval = "";
357                 p->tval = FLD | STR | DONTFREE;
358         }
359 }
360
361 void newfld(int n)      /* add field n after end of existing lastfld */
362 {
363         if (n > nfields)
364                 growfldtab(n);
365         cleanfld(lastfld+1, n);
366         lastfld = n;
367         setfval(nfloc, (Awkfloat) n);
368 }
369
370 Cell *fieldadr(int n)   /* get nth field */
371 {
372         if (n < 0)
373                 FATAL("trying to access field %d", n);
374         if (n > nfields)        /* fields after NF are empty */
375                 growfldtab(n);  /* but does not increase NF */
376         return(fldtab[n]);
377 }
378
379 void growfldtab(int n)  /* make new fields up to at least $n */
380 {
381         int nf = 2 * nfields;
382
383         if (n > nf)
384                 nf = n;
385         fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
386         if (fldtab == NULL)
387                 FATAL("out of space creating %d fields", nf);
388         makefields(nfields+1, nf);
389         nfields = nf;
390 }
391
392 int refldbld(char *rec, char *fs)       /* build fields from reg expr in FS */
393 {
394         /* this relies on having fields[] the same length as $0 */
395         /* the fields are all stored in this one array with \0's */
396         char *fr;
397         void *p;
398         int i, tempstat, n;
399
400         n = strlen(rec);
401         if (n > fieldssize) {
402                 xfree(fields);
403                 if ((fields = (char *) malloc(n+1)) == NULL)
404                         FATAL("out of space for fields in refldbld %d", n);
405                 fieldssize = n;
406         }
407         fr = fields;
408         *fr = '\0';
409         if (*rec == '\0')
410                 return 0;
411         p = compre(fs);
412            dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
413         for (i = 1; ; i++) {
414                 if (i > nfields)
415                         growfldtab(i);
416                 if (freeable(fldtab[i]))
417                         xfree(fldtab[i]->sval);
418                 fldtab[i]->tval = FLD | STR | DONTFREE;
419                 fldtab[i]->sval = fr;
420                    dprintf( ("refldbld: i=%d\n", i) );
421                 if (nematch(p, rec, rec)) {
422                            dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
423                         strncpy(fr, rec, patbeg-rec);
424                         fr += patbeg - rec + 1;
425                         *(fr-1) = '\0';
426                         rec = patbeg + patlen;
427                 } else {
428                            dprintf( ("no match %s\n", rec) );
429                         strcpy(fr, rec);
430                         break;
431                 }
432         }
433         return i;               
434 }
435
436 void recbld(void)       /* create $0 from $1..$NF if necessary */
437 {
438         int i;
439         char *r, *p;
440
441         if (donerec == 1)
442                 return;
443         r = record;
444         for (i = 1; i <= *NF; i++) {
445                 p = getsval(fldtab[i]);
446                 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
447                         FATAL("created $0 `%.30s...' too long", record);
448                 while ((*r = *p++) != 0)
449                         r++;
450                 if (i < *NF) {
451                         if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
452                                 FATAL("created $0 `%.30s...' too long", record);
453                         for (p = *OFS; (*r = *p++) != 0; )
454                                 r++;
455                 }
456         }
457         if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
458                 FATAL("built giant record `%.30s...'", record);
459         *r = '\0';
460            dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
461
462         if (freeable(fldtab[0]))
463                 xfree(fldtab[0]->sval);
464         fldtab[0]->tval = REC | STR | DONTFREE;
465         fldtab[0]->sval = record;
466
467            dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
468            dprintf( ("recbld = |%s|\n", record) );
469         donerec = 1;
470 }
471
472 int     errorflag       = 0;
473
474 void yyerror(char *s)
475 {
476         SYNTAX(s);
477 }
478
479 void SYNTAX(char *fmt, ...)
480 {
481         extern char *cmdname, *curfname;
482         static int been_here = 0;
483         va_list varg;
484
485         if (been_here++ > 2)
486                 return;
487         fprintf(stderr, "%s: ", cmdname);
488         va_start(varg, fmt);
489         vfprintf(stderr, fmt, varg);
490         va_end(varg);
491         if(compile_time == 1 && cursource() != NULL)
492                 fprintf(stderr, " at %s:%d", cursource(), lineno);
493         else
494                 fprintf(stderr, " at line %d", lineno);
495         if (curfname != NULL)
496                 fprintf(stderr, " in function %s", curfname);
497         fprintf(stderr, "\n");
498         errorflag = 2;
499         eprint();
500 }
501
502 void fpecatch(int n)
503 {
504         FATAL("floating point exception %d", n);
505 }
506
507 extern int bracecnt, brackcnt, parencnt;
508
509 void bracecheck(void)
510 {
511         int c;
512         static int beenhere = 0;
513
514         if (beenhere++)
515                 return;
516         while ((c = input()) != EOF && c != '\0')
517                 bclass(c);
518         bcheck2(bracecnt, '{', '}');
519         bcheck2(brackcnt, '[', ']');
520         bcheck2(parencnt, '(', ')');
521 }
522
523 void bcheck2(int n, int c1, int c2)
524 {
525         if (n == 1)
526                 fprintf(stderr, "\tmissing %c\n", c2);
527         else if (n > 1)
528                 fprintf(stderr, "\t%d missing %c's\n", n, c2);
529         else if (n == -1)
530                 fprintf(stderr, "\textra %c\n", c2);
531         else if (n < -1)
532                 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
533 }
534
535 void FATAL(char *fmt, ...)
536 {
537         extern char *cmdname;
538         va_list varg;
539
540         fflush(stdout);
541         fprintf(stderr, "%s: ", cmdname);
542         va_start(varg, fmt);
543         vfprintf(stderr, fmt, varg);
544         va_end(varg);
545         error();
546         if (dbg > 1)            /* core dump if serious debugging on */
547                 abort();
548         exit(2);
549 }
550
551 void WARNING(char *fmt, ...)
552 {
553         extern char *cmdname;
554         va_list varg;
555
556         fflush(stdout);
557         fprintf(stderr, "%s: ", cmdname);
558         va_start(varg, fmt);
559         vfprintf(stderr, fmt, varg);
560         va_end(varg);
561         error();
562 }
563
564 void error()
565 {
566         extern Node *curnode;
567         int line;
568
569         fprintf(stderr, "\n");
570         if (compile_time != 2 && NR && *NR > 0) {
571                 if (strcmp(*FILENAME, "-") != 0)
572                         fprintf(stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
573                 else
574                         fprintf(stderr, " input record number %d", (int) (*FNR));
575                 fprintf(stderr, "\n");
576         }
577         if (compile_time != 2 && curnode)
578                 line = curnode->lineno;
579         else if (compile_time != 2 && lineno)
580                 line = lineno;
581         else
582                 line = -1;
583         if (compile_time == 1 && cursource() != NULL){
584                 if(line >= 0)
585                         fprintf(stderr, " source %s:%d", cursource(), line);
586                 else
587                         fprintf(stderr, " source file %s", cursource());
588         }else if(line >= 0)
589                 fprintf(stderr, " source line %d", line);
590         fprintf(stderr, "\n");
591         eprint();
592 }
593
594 void eprint(void)       /* try to print context around error */
595 {
596         char *p, *q;
597         int c;
598         static int been_here = 0;
599         extern char ebuf[], *ep;
600
601         if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
602                 return;
603         p = ep - 1;
604         if (p > ebuf && *p == '\n')
605                 p--;
606         for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
607                 ;
608         while (*p == '\n')
609                 p++;
610         fprintf(stderr, " context is\n\t");
611         for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
612                 ;
613         for ( ; p < q; p++)
614                 if (*p)
615                         putc(*p, stderr);
616         fprintf(stderr, " >>> ");
617         for ( ; p < ep; p++)
618                 if (*p)
619                         putc(*p, stderr);
620         fprintf(stderr, " <<< ");
621         if (*ep)
622                 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
623                         putc(c, stderr);
624                         bclass(c);
625                 }
626         putc('\n', stderr);
627         ep = ebuf;
628 }
629
630 void bclass(int c)
631 {
632         switch (c) {
633         case '{': bracecnt++; break;
634         case '}': bracecnt--; break;
635         case '[': brackcnt++; break;
636         case ']': brackcnt--; break;
637         case '(': parencnt++; break;
638         case ')': parencnt--; break;
639         }
640 }
641
642 double errcheck(double x, char *s)
643 {
644
645         if (errno == EDOM) {
646                 errno = 0;
647                 WARNING("%s argument out of domain", s);
648                 x = 1;
649         } else if (errno == ERANGE) {
650                 errno = 0;
651                 WARNING("%s result out of range", s);
652                 x = 1;
653         }
654         return x;
655 }
656
657 int isclvar(char *s)    /* is s of form var=something ? */
658 {
659         char *os = s;
660
661         if (!isalpha(*s) && *s != '_')
662                 return 0;
663         for ( ; *s; s++)
664                 if (!(isalnum(*s) || *s == '_'))
665                         break;
666         return *s == '=' && s > os && *(s+1) != '=';
667 }
668
669 /* strtod is supposed to be a proper test of what's a valid number */
670
671 #include <math.h>
672 int is_number(char *s)
673 {
674         double r;
675         char *ep;
676
677         /*
678          * fast could-it-be-a-number check before calling strtod,
679          * which takes a surprisingly long time to reject non-numbers.
680          */
681         switch (*s) {
682         case '0': case '1': case '2': case '3': case '4':
683         case '5': case '6': case '7': case '8': case '9':
684         case '\t':
685         case '\n':
686         case '\v':
687         case '\f':
688         case '\r':
689         case ' ':
690         case '-':
691         case '+':
692         case '.':
693         case 'n':               /* nans */
694         case 'N':
695         case 'i':               /* infs */
696         case 'I':
697                 break;
698         default:
699                 return 0;       /* can't be a number */
700         }
701
702         errno = 0;
703         r = strtod(s, &ep);
704         if (ep == s || r == HUGE_VAL || errno == ERANGE)
705                 return 0;
706         while (*ep == ' ' || *ep == '\t' || *ep == '\n')
707                 ep++;
708         if (*ep == '\0')
709                 return 1;
710         else
711                 return 0;
712 }