|
|
1.1 ! root 1: /* ! 2: * getflds - break a line into fields ! 3: * ! 4: * General strategy: ptrs is a pointer to an array of ! 5: * character pointers. This array is used to hold the ! 6: * results of each call to getflds. Expandptrs() uses ! 7: * realloc to grow this array as needed. Each pointer in ! 8: * the array points into the buffer addressed by str, ! 9: * so all the strings returned by getflds are really ! 10: * contiguous. Expandstr() uses realloc to grow this buffer ! 11: * as needed; after it has done so it must relocate all ! 12: * the pointers into the buffer because it may have moved. ! 13: * ! 14: * Both expandstrs and expandptrs return nonzero for failure. ! 15: * ! 16: * Ptrs and str are initially null. In the (unlikely) ! 17: * event that an attempt to grow one of them fails, the ! 18: * corresponding pointer is set back to null. ! 19: */ ! 20: ! 21: #include <stdio.h> ! 22: #include <setjmp.h> ! 23: ! 24: /* how many elements to expand str and ptrs at a time */ ! 25: #define STRCHUNK 512 ! 26: #define PTRCHUNK 128 ! 27: ! 28: char *malloc(), *realloc(); ! 29: static char **ptrs = NULL, *str = NULL; ! 30: static unsigned ptrsize = 0, strsize = 0; ! 31: ! 32: static ! 33: expandptrs() ! 34: { ! 35: ptrsize += PTRCHUNK; ! 36: ptrs = (char **) (ptrs? realloc (ptrs, ptrsize * sizeof (char *)): ! 37: malloc (ptrsize * sizeof (char *))); ! 38: if (ptrs == NULL) { ! 39: ptrsize = 0; ! 40: return 1; ! 41: } ! 42: return 0; ! 43: } ! 44: ! 45: static ! 46: expandstr() ! 47: { ! 48: register char *newstr; ! 49: register unsigned n; ! 50: ! 51: strsize += STRCHUNK; ! 52: newstr = str? realloc (str, strsize): malloc (strsize); ! 53: if (newstr == NULL) { ! 54: str = NULL; ! 55: strsize = 0; ! 56: return 1; ! 57: } ! 58: ! 59: /* relocate the ptrs array */ ! 60: for (n = 0; n < ptrsize; n++) ! 61: ptrs[n] = newstr + (ptrs[n] - str); ! 62: ! 63: str = newstr; ! 64: return 0; ! 65: } ! 66: ! 67: char ** ! 68: getflds (f) ! 69: register FILE *f; ! 70: { ! 71: register int c; ! 72: register unsigned nptr = 0, nstr = 0; ! 73: ! 74: /* try to read the first character of the line */ ! 75: c = getc (f); ! 76: ! 77: /* a line beginning with # is a comment */ ! 78: while (c == '#') { ! 79: do c = getc (f); ! 80: while (c != '\n' && c != EOF); ! 81: if (c == '\n') ! 82: c = getc (f); ! 83: } ! 84: ! 85: /* EOF at the beginning of the line is real */ ! 86: if (c == EOF) ! 87: return NULL; ! 88: ! 89: /* one iteration per field */ ! 90: do { ! 91: /* 0 outside a quoted string, otherwise the type of quote */ ! 92: register quote = 0; ! 93: ! 94: /* skip leading white space */ ! 95: while (c == ' ' || c == '\t') ! 96: c = getc (f); ! 97: ! 98: /* maybe it wan't a field after all */ ! 99: if (c == '\n' || c == EOF) ! 100: break; ! 101: ! 102: /* make room for the field pointer and plant it */ ! 103: if (nptr >= ptrsize) ! 104: if (expandptrs()) ! 105: return NULL; ! 106: ptrs[nptr++] = str + nstr; ! 107: ! 108: /* one iteration per character or escape sequence */ ! 109: while ((c != ' ' && c != '\t' || quote) && c != '\n' && c != EOF) { ! 110: ! 111: /* check for escape sequence */ ! 112: if (c == '\\') { ! 113: c = getc (f); ! 114: switch (c) { ! 115: ! 116: /* C escapes for newline, etc. */ ! 117: case 'b': c = '\b'; break; ! 118: case 'f': c = '\f'; break; ! 119: case 'n': c = '\n'; break; ! 120: case 'r': c = '\r'; break; ! 121: case 't': c = '\t'; break; ! 122: case 'v': c = '\v'; break; ! 123: ! 124: /* these characters stand for themselves */ ! 125: case '\'': case '"': case '#': ! 126: case ' ': case '\t': case '\\': ! 127: break; ! 128: ! 129: /* backslash, newline is ignored */ ! 130: case '\n': ! 131: c = getc (f); ! 132: continue; ! 133: ! 134: /* backslash, octal digits */ ! 135: case '0': case '1': case '2': case '3': ! 136: case '4': case '5': case '6': case '7': ! 137: { ! 138: register r = c - '0'; ! 139: register n = 2; ! 140: do { ! 141: c = getc (f); ! 142: if (c < '0' || c > '7') { ! 143: ungetc (c, f); ! 144: break; ! 145: } ! 146: r = (r<<3) + c - '0'; ! 147: } while (--n > 0); ! 148: c = r; ! 149: } ! 150: break; ! 151: ! 152: /* else treat the backslash as an ordinary char */ ! 153: default: ! 154: ungetc (c, f); ! 155: c = '\\'; ! 156: break; ! 157: } ! 158: ! 159: /* not a backslash, check for a quote */ ! 160: } else if (c == '\'' || c == '"') { ! 161: ! 162: /* beginning of a quoted string */ ! 163: if (!quote) { ! 164: quote = c; ! 165: c = getc (f); ! 166: continue; ! 167: ! 168: /* end of a quoted string */ ! 169: } else if (c == quote) { ! 170: quote = 0; ! 171: c = getc (f); ! 172: continue; ! 173: } ! 174: ! 175: /* ! 176: * otherwise we're inside a quoted string ! 177: * and we've seen the "other" quote, which ! 178: * is now just an ordinary character. ! 179: */ ! 180: } ! 181: ! 182: /* we have a character; put it in the string */ ! 183: if (nstr >= strsize) ! 184: if (expandstr()) ! 185: return NULL; ! 186: str[nstr++] = c; ! 187: c = getc (f); ! 188: } ! 189: ! 190: /* end of field; plant a null char at the end of the string */ ! 191: if (nstr >= strsize) ! 192: if (expandstr()) ! 193: return NULL; ! 194: str[nstr++] = '\0'; ! 195: ! 196: } while (c != '\n' && c != EOF); ! 197: ! 198: /* end of line; put a null pointer at the end of the array */ ! 199: if (nptr >= ptrsize) ! 200: if (expandptrs()) ! 201: return NULL; ! 202: ptrs[nptr++] = NULL; ! 203: ! 204: return ptrs; ! 205: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.