summaryrefslogtreecommitdiff
path: root/common/parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'common/parser.cc')
-rw-r--r--common/parser.cc250
1 files changed, 250 insertions, 0 deletions
diff --git a/common/parser.cc b/common/parser.cc
new file mode 100644
index 0000000..3311e45
--- /dev/null
+++ b/common/parser.cc
@@ -0,0 +1,250 @@
+/*
+ * RTFL
+ *
+ * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version; with the following exception:
+ *
+ * The copyright holders of RTFL give you permission to link this file
+ * statically or dynamically against all versions of the graphviz
+ * library, which are published by AT&T Corp. under one of the following
+ * licenses:
+ *
+ * - Common Public License version 1.0 as published by International
+ * Business Machines Corporation (IBM), or
+ * - Eclipse Public License version 1.0 as published by the Eclipse
+ * Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "parser.hh"
+
+#include <string.h>
+#include <ctype.h>
+
+namespace rtfl {
+
+namespace tools {
+
+void Parser::setLinesSource (LinesSource *source)
+{
+}
+
+void Parser::processLine (char *line)
+{
+ char *lineCopy = strdup (line);
+
+ if (strncmp (lineCopy, "[rtfl]", 6) == 0) {
+ // Pre-version: starts with "[rtfl]".
+
+ char **parts = split (lineCopy + 6, 5);
+
+ if (parts[1] && parts[2] && parts[3]) {
+ // Notice that parts[4] (arguments) is allowed to be NULL here.
+ CommonLineInfo info =
+ { parts[0], atoi(parts[1]), atoi(parts[2]), line };
+ processCommand (&info, parts[3], parts[4]);
+ } else
+ fprintf (stderr, "Incomplete line:\n%s\n", line);
+
+ freeSplit (parts);
+ } else if (strncmp (lineCopy, "[rtfl-", 6) == 0) {
+ // Versioned: starts with "[rtfl-<module>-<major>.<minor>]".
+
+ int i = 6;
+ while (isalpha (lineCopy[i]))
+ i++;
+
+ if (lineCopy[i] != '-')
+ fprintf (stderr, "Expected '-' after module:\n%s\n", line);
+ else {
+ char *module = new char[i - 6 + 1];
+ memcpy (module, lineCopy + 6, (i - 6) * sizeof (char));
+ module[i - 6] = 0;
+
+ i++;
+ if (!isdigit (lineCopy[i]))
+ fprintf (stderr, "Missing major version:\n%s\n", line);
+ else {
+ int majorVersion = 0, minorVersion = 0;
+
+ while (isdigit (lineCopy[i])) {
+ majorVersion = 10 * majorVersion + (lineCopy[i] - '0');
+ i++;
+ }
+
+ if (majorVersion == 0)
+ fprintf (stderr, "Major version must be positive:\n%s\n", line);
+ else if (lineCopy[i] != '.')
+ fprintf (stderr, "Expected '.' after major version:\n%s\n",
+ line);
+ else if (!isdigit (lineCopy[i + 1]))
+ fprintf (stderr, "Missing minor version:\n%s\n", line);
+ else {
+ i++;
+ while (isdigit (lineCopy[i])) {
+ minorVersion = 10 * minorVersion + (lineCopy[i] - '0');
+ i++;
+ }
+
+ if (lineCopy[i] != ']')
+ fprintf (stderr, "Expected ']' after minor version:\n%s\n",
+ line);
+ else {
+ char **parts = splitEscaped (lineCopy + i + 1);
+
+ if (parts[1] && parts[2] && parts[3]) {
+ // Notice that parts[4] (first argument) is allowed to be
+ // NULL here.
+ CommonLineInfo info = { parts[0], atoi(parts[1]),
+ atoi(parts[2]), line };
+ processVCommand (&info, module, majorVersion, minorVersion,
+ parts[3], parts + 4);
+ } else
+ fprintf (stderr, "Incomplete line:\n%s\n", line);
+
+ freeSplitEscaped (parts);
+ }
+ }
+ }
+
+ delete[] module;
+ }
+ }
+
+ free (lineCopy);
+}
+
+void Parser::finish ()
+{
+}
+
+void Parser::timeout (int type)
+{
+}
+
+char **Parser::splitEscaped (char *txt)
+{
+ int numParts;
+ char **parts;
+
+ scanSplit (txt, &numParts, NULL);
+ parts = new char*[numParts + 1];
+ scanSplit (txt, NULL, parts);
+ parts[numParts] = NULL;
+
+ for (int i = 0; i < numParts; i++)
+ unquote (parts[i]);
+
+ return parts;
+}
+
+void Parser::scanSplit (char *txt, int *numParts, char **parts)
+{
+ int iChar, iPart;
+ bool quoted;
+
+ if (numParts)
+ *numParts = 1;
+
+ if (parts)
+ parts[0] = txt;
+
+ for (iChar = 0, iPart = 1; txt[iChar]; iChar++) {
+ if (txt[iChar] == '\\' && txt[iChar + 1]) {
+ iChar++;
+ quoted = true;
+ } else
+ quoted = false;
+
+ if (!quoted && txt[iChar] == ':') {
+ if (parts) {
+ txt[iChar] = 0;
+ parts[iPart] = txt + iChar + 1;
+ }
+
+ iPart++;
+
+ if (numParts)
+ (*numParts)++;
+ }
+ }
+}
+
+void Parser::unquote (char *txt)
+{
+ int i, j;
+ for (i = 0, j = 0; txt[i]; i++, j++) {
+ if (txt[i] == '\\' && txt[i + 1])
+ i++;
+ txt[j] = txt[i];
+ }
+ txt[j] = 0;
+}
+
+// Free result of splitEscaped().
+void Parser::freeSplitEscaped (char **parts)
+{
+ delete[] parts;
+}
+
+// Split without escaping.
+char **Parser::split (char *txt, int maxNum)
+{
+ // Only maxNum splits. If less parts are found, less parts are
+ // returned, so the caller should check the result (first part is
+ // always defined). Notice that the original text buffer (txt) is
+ // destroyed, for speed.
+
+ //printf ("===> split ('%s', %d)\n", txt, maxNum);
+
+ char **parts = new char*[maxNum + 1];
+
+ char *start = txt;
+ int i = 0;
+ while (i < maxNum) {
+ char *end = start;
+ while (*end != 0 && *end != ':') end++;
+ int endOfTxt = *end == 0;
+
+ //printf (" start '%s'\n", start);
+ //printf (" end '%s' (%d character(s))\n",
+ // end, (int)(end - start));
+
+ parts[i] = start;
+
+ if (i < maxNum -1)
+ *end = 0;
+
+ //printf ("---> %d: '%s'\n", i, start);
+
+ i++;
+ if (endOfTxt)
+ break;
+
+ start = endOfTxt ? end : end + 1;
+ }
+
+ parts[i] = NULL;
+ return parts;
+}
+
+// Free result of split().
+void Parser::freeSplit (char **parts)
+{
+ delete[] parts;
+}
+
+} // namespace tools
+
+} // namespace rtfl