comparison src/main/java/nl/cwi/monetdb/mcl/parser/HeaderLineParser.java @ 0:a5a898f6886c

Copy of MonetDB java directory changeset e6e32756ad31.
author Sjoerd Mullender <sjoerd@acm.org>
date Wed, 21 Sep 2016 09:34:48 +0200 (2016-09-21)
parents
children e67d58485172 b9b35ca2eec2
comparison
equal deleted inserted replaced
-1:000000000000 0:a5a898f6886c
1 /*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V.
7 */
8
9 package nl.cwi.monetdb.mcl.parser;
10
11
12 /**
13 * The HeaderLineParser is a generic MCLParser that extracts values from
14 * a metadata header in the MCL protocol either as string or integer
15 * values.
16 *
17 * @author Fabian Groffen <Fabian.Groffen>
18 */
19 public class HeaderLineParser extends MCLParser {
20 private int type;
21
22 public final static int NAME = 1;
23 public final static int LENGTH = 2;
24 public final static int TABLE = 3;
25 public final static int TYPE = 4;
26
27 /**
28 * Constructs a HeaderLineParser which expects columncount columns.
29 *
30 * @param columncount the number of columns in the to be parsed string
31 */
32 public HeaderLineParser(int columncount) {
33 super(columncount);
34 }
35
36 /**
37 * Parses the given String source as header line. If source cannot
38 * be parsed, an MCLParseException is thrown. The columncount argument
39 * given during construction is used for allocation of the backing
40 * array. Parsing a header line with has more fields will therefore
41 * result in a crash. While this seems illogical, the caller should
42 * know this size, since the StartOfHeader contains this
43 * information.
44 *
45 * @param source a String which should be parsed
46 * @return the type of then parsed header line
47 * @throws MCLParseException if an error occurs during parsing
48 */
49 @Override
50 public int parse(String source) throws MCLParseException {
51 char[] chrLine = source.toCharArray();
52 int len = chrLine.length;
53 int pos = 0;
54 boolean foundChar = false;
55 boolean nameFound = false;
56 // find header name
57 for (int i = len - 1; i >= 0; i--) {
58 switch (chrLine[i]) {
59 case ' ':
60 case '\n':
61 case '\t':
62 case '\r':
63 if (!foundChar) {
64 len = i - 1;
65 } else {
66 pos = i + 1;
67 }
68 break;
69 case '#':
70 // found!
71 nameFound = true;
72 if (pos == 0) pos = i + 1;
73 i = 0; // force the loop to terminate
74 break;
75 default:
76 foundChar = true;
77 pos = 0;
78 break;
79 }
80 }
81 if (!nameFound)
82 throw new MCLParseException("invalid header, no header name found", pos);
83
84 // depending on the name of the header, we continue
85 switch (chrLine[pos]) {
86 case 'n':
87 if (len - pos == 4 &&
88 source.regionMatches(pos + 1, "name", 1, 3))
89 {
90 getValues(chrLine, 2, pos - 3);
91 type = NAME;
92 }
93 break;
94 case 'l':
95 if (len - pos == 6 &&
96 source.regionMatches(pos + 1, "length", 1, 5))
97 {
98 getIntValues(chrLine, 2, pos - 3);
99 type = LENGTH;
100 }
101 break;
102 case 't':
103 if (len - pos == 4 &&
104 source.regionMatches(pos + 1, "type", 1, 3))
105 {
106 getValues(chrLine, 2, pos - 3);
107 type = TYPE;
108 } else if (len - pos == 10 &&
109 source.regionMatches(pos + 1, "table_name", 1, 9))
110 {
111 getValues(chrLine, 2, pos - 3);
112 type = TABLE;
113 }
114 break;
115 default:
116 throw new MCLParseException("unknown header: " +
117 (new String(chrLine, pos, len - pos)));
118 }
119
120 // adjust colno
121 reset();
122
123 return type;
124 }
125
126 /**
127 * Returns an array of Strings containing the values between
128 * ',\t' separators. Note that no quoting/dequoting is done in this
129 * method.
130 *
131 * @param chrLine a character array holding the input data
132 * @param start where the relevant data starts
133 * @param stop where the relevant data stops
134 */
135 final private void getValues(char[] chrLine, int start, int stop) {
136 int elem = 0;
137
138 for (int i = start + 1; i < stop; i++) {
139 if (chrLine[i] == '\t' && chrLine[i - 1] == ',') {
140 values[elem++] =
141 new String(chrLine, start, i - 1 - start);
142 start = i + 1;
143 }
144 }
145 // add the left over part
146 values[elem++] = new String(chrLine, start, stop - start);
147 }
148
149 /**
150 * Returns an array of ints containing the values between
151 * ',\t' separators.
152 *
153 * @param chrLine a character array holding the input data
154 * @param start where the relevant data starts
155 * @param stop where the relevant data stops
156 */
157 final private void getIntValues(char[] chrLine, int start, int stop)
158 throws MCLParseException
159 {
160 int elem = 0;
161 int tmp = 0;
162
163 for (int i = start; i < stop; i++) {
164 if (chrLine[i] == ',' && chrLine[i + 1] == '\t') {
165 intValues[elem++] = tmp;
166 tmp = 0;
167 start = i++;
168 } else {
169 tmp *= 10;
170 // note: don't use Character.isDigit() here, because
171 // we only want ISO-LATIN-1 digits
172 if (chrLine[i] >= '0' && chrLine[i] <= '9') {
173 tmp += (int)chrLine[i] - (int)'0';
174 } else {
175 throw new MCLParseException("expected a digit in " + new String(chrLine) + " at " + i);
176 }
177 }
178 }
179 // add the left over part
180 intValues[elem++] = tmp;
181 }
182 }