about summary refs log tree commit diff
path: root/generator
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2018-10-07 17:43:51 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2018-10-07 17:43:51 +0000
commite6563555c0e86e2d28cae402b35e1951a686a9a8 (patch)
treef0fc090692d575d6211193966f6510737beff5ea /generator
parentbb62d1024321fa0552ef5b9f27b91660ec370ea0 (diff)
downloadnetpbm-mirror-e6563555c0e86e2d28cae402b35e1951a686a9a8.tar.gz
netpbm-mirror-e6563555c0e86e2d28cae402b35e1951a686a9a8.tar.xz
netpbm-mirror-e6563555c0e86e2d28cae402b35e1951a686a9a8.zip
Split large function; make structured
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@3393 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r--generator/pamtris/input.c791
-rw-r--r--generator/pamtris/input.h22
-rw-r--r--generator/pamtris/pamtris.c10
3 files changed, 430 insertions, 393 deletions
diff --git a/generator/pamtris/input.c b/generator/pamtris/input.c
index f38d4a39..2ea35734 100644
--- a/generator/pamtris/input.c
+++ b/generator/pamtris/input.c
@@ -11,6 +11,7 @@
 
 #include "netpbm/mallocvar.h"
 #include "netpbm/pm.h"
+#include "netpbm/nstring.h"
 
 #include "limits_pamtris.h"
 #include "framebuffer.h"
@@ -65,13 +66,13 @@ typedef struct {
 
 
 static void
-clear_attribs(state_info * const si,
-              int32_t      const maxval,
-              int16_t      const num_attribs) {
+clearAttribs(state_info * const si,
+             int32_t      const maxval,
+             int16_t      const num_attribs) {
 
     unsigned int i;
 
-    for (i = 0; i < num_attribs; i++) {
+    for (i = 0; i < num_attribs; ++i) {
         si->curr_attribs[i] = maxval;
     }
 }
@@ -79,20 +80,20 @@ clear_attribs(state_info * const si,
 
 
 void
-init_input_processor(input_info * const ii) {
+input_init(Input * const inputP) {
 
-    ii->buffer = NULL;
-    ii->length = 0;
-    ii->number = 1;
+    inputP->buffer = NULL;
+    inputP->length = 0;
+    inputP->number = 1;
 }
 
 
 
 void
-free_input_processor(input_info * const ii) {
+input_term(Input * const inputP) {
 
-    if (ii->buffer)
-        free(ii->buffer);
+    if (inputP->buffer)
+        free(inputP->buffer);
 }
 
 
@@ -104,14 +105,14 @@ typedef struct {
 -----------------------------------------------------------------------------*/
     char * begin;
     char * end;
-} token;
+} Token;
 
 
 
-static token
-next_token(char * const startPos) {
+static Token
+nextToken(char * const startPos) {
 
-    token retval;
+    Token retval;
     char * p;
 
     for (p = startPos; *p && isspace(*p); ++p);
@@ -128,9 +129,9 @@ next_token(char * const startPos) {
 
 
 static bool
-string_is_valid(const char * const target,
-                const char * const srcBegin,
-                const char * const srcEnd) {
+stringIsValid(const char * const target,
+              const char * const srcBegin,
+              const char * const srcEnd) {
 
     unsigned int charsMatched;
     const char * p;
@@ -150,17 +151,17 @@ string_is_valid(const char * const target,
 
 
 static void
-init_state(state_info * const si) {
+initState(state_info * const siP) {
 
-    si->next = 0;
-    si->draw = false;
-    si->mode = DRAW_MODE_TRIANGLES;
+    siP->next = 0;
+    siP->draw = false;
+    siP->mode = DRAW_MODE_TRIANGLES;
 }
 
 
 
 static void
-make_lowercase(token const t) {
+makeLowercase(Token const t) {
 
     char * p;
 
@@ -171,7 +172,7 @@ make_lowercase(token const t) {
 
 
 static void
-remove_comments(char * const str) {
+removeComments(char * const str) {
 
     char * p;
 
@@ -186,472 +187,510 @@ remove_comments(char * const str) {
 
 
 
-int
-process_next_command(input_info           * const line,
-                     struct boundary_info * const bi,
-                     framebuffer_info     * const fbi) {
-/*----------------------------------------------------------------------------
-  Doesn't necessarily process a command, just the next line of input, which
-  may be empty. Always returns 1, except when it cannot read any more lines of
-  input, an image buffer reallocation fails, or a "q" command is found in the
-  input -- in such cases it returns 0.
------------------------------------------------------------------------------*/
-    static state_info state;
-
-    token nt;
-
-    long int i_args[MAX_NUM_ATTRIBS];
-        /* For storing potential integer arguments. */
-    char * strtol_end;
-        /* To compare against nt.end when checking for errors with strtol */
-    bool unrecognized_cmd;
-        /* To print out an error message in case an unrecognized command was
-           given.
-        */
-    bool unrecognized_arg;
-        /* To print out an error message in case an unrecognized argument was
-           given.
-        */
-    bool must_break_out;
-        /* To break out of the below switch statement when an invalid argument
-           is found.
-        */
-    bool ok;
-        /* Indicates whether the input line was OK so that we can print out a
-           warning in case of excess arguments.
-        */
-
-    /* initial values */
-    strtol_end = NULL;
-    unrecognized_cmd = false;
-    unrecognized_arg = false;
-    must_break_out = false;
-    ok = false;
-
-    if (!state.initialized) {
-        init_state(&state);
-        clear_attribs(&state, fbi->maxval, fbi->num_attribs);
-
-        state.initialized = true;
+static void
+processM(Token *       const ntP,
+         state_info *  const stateP,
+         bool *        const unrecognizedCmdP,
+         const char ** const errorP) {
+
+    if (!stringIsValid(CMD_SET_MODE, ntP->begin, ntP->end)) {
+        *unrecognizedCmdP = true;
+    } else {
+        *ntP = nextToken(ntP->end);
+
+        *unrecognizedCmdP = false;
+
+        if (*ntP->begin == '\0')
+            pm_asprintf(errorP, "syntax error");
+        else {
+            makeLowercase(*ntP);
+
+            switch (*ntP->begin) {
+            case 't':
+                if (!stringIsValid(ARG_TRIANGLES, ntP->begin, ntP->end))
+                    pm_asprintf(errorP, "unrecognized drawing mode");
+                else {
+                    stateP->mode = DRAW_MODE_TRIANGLES;
+                    stateP->draw = false;
+                    stateP->next = 0;
+
+                    *errorP = NULL;
+                }
+                break;
+            case 's':
+                if (!stringIsValid(ARG_STRIP, ntP->begin, ntP->end))
+                    pm_asprintf(errorP, "unrecognized drawing mode");
+                else {
+                    stateP->mode = DRAW_MODE_STRIP;
+                    stateP->draw = false;
+                    stateP->next = 0;
+
+                    *errorP = NULL;
+                }
+                break;
+            case 'f':
+                if (!stringIsValid(ARG_FAN, ntP->begin, ntP->end))
+                    pm_asprintf(errorP, "unrecognized drawing mode");
+                else {
+                    stateP->mode = DRAW_MODE_FAN;
+                    stateP->draw = false;
+                    stateP->next = 0;
+
+                    *errorP = NULL;
+                }
+                break;
+            default:
+                pm_asprintf(errorP, "unrecognized drawing mode");
+            }
+        }
     }
+}
 
-    {
-        int eof;
-        size_t lineLen;
-
-        pm_getline(stdin, &line->buffer, &line->length, &eof, &lineLen);
-
-        if (eof)
-            return 0;
-    }
 
-    remove_comments(line->buffer);
 
-    nt = next_token(line->buffer);
+static void
+processA(Token *            const ntP,
+         state_info *       const stateP,
+         framebuffer_info * const fbiP,
+         bool *             const unrecognizedCmdP,
+         long int *         const iArgs,
+         const char **      const errorP) {
 
-    make_lowercase(nt);
+    if (!stringIsValid(CMD_SET_ATTRIBS, ntP->begin, ntP->end)) {
+        *unrecognizedCmdP = true;
+    } else {
+        unsigned int i;
 
-    switch (*nt.begin) {
-    case 'm':
-        if (!string_is_valid(CMD_SET_MODE, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
+        *unrecognizedCmdP = false;
 
-            break;
-        }
+        for (i = 0, *errorP = NULL; i < fbiP->num_attribs && !*errorP; ++i) {
+            char * strtolEnd;
 
-        nt = next_token(nt.end);
+            *ntP = nextToken(ntP->end);
 
-        if (*nt.begin == '\0') {
-            pm_errormsg(SYNTAX_ERROR, line->number);
+            iArgs[i] = strtol(ntP->begin, &strtolEnd, 10);
 
-            break;
+            if (*ntP->begin == '\0' || strtolEnd != ntP->end)
+                pm_asprintf(errorP, "syntax error");
+            else {
+                if (iArgs[i] < 0 || iArgs[i] > fbiP->maxval)
+                    pm_asprintf(errorP, "argument(s) out of bounds");
+            }
         }
 
-        make_lowercase(nt);
+        if (!*errorP) {
+            unsigned int i;
 
-        switch(*nt.begin) {
-        case 't':
-            if (!string_is_valid(ARG_TRIANGLES, nt.begin, nt.end)) {
-                unrecognized_arg = true;
+            for (i = 0; i < fbiP->num_attribs; ++i)
+                stateP->curr_attribs[i] = iArgs[i];
+        }
+    }
+}
 
-                break;
-            }
 
-            state.mode = DRAW_MODE_TRIANGLES;
-            state.draw = false;
-            state.next = 0;
 
-            ok = true;
+static void
+processV(Token *                const ntP,
+         state_info *           const stateP,
+         struct boundary_info * const biP,
+         framebuffer_info *     const fbiP,
+         bool *                 const unrecognizedCmdP,
+         long int *             const iArgs,
+         const char **          const errorP) {
 
-            break;
-        case 's':
-            if (!string_is_valid(ARG_STRIP, nt.begin, nt.end)) {
-                unrecognized_arg = true;
+    if (!stringIsValid(CMD_VERTEX, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        unsigned int i;
 
-                break;
-            }
+        *unrecognizedCmdP = false;
 
-            state.mode = DRAW_MODE_STRIP;
-            state.draw = false;
-            state.next = 0;
+        for (i = 0, *errorP = NULL; i < 4 && !*errorP; ++i) {
+            char * strtolEnd;
 
-            ok = true;
+            *ntP = nextToken(ntP->end);
 
-            break;
-        case 'f':
-            if (!string_is_valid(ARG_FAN, nt.begin, nt.end)) {
-                unrecognized_arg = true;
+            iArgs[i] = strtol(ntP->begin, &strtolEnd, 10);
 
-                break;
+            if (*ntP->begin == '\0') {
+                if (i != 3)
+                    pm_asprintf(errorP, "syntax error");
+                else
+                    iArgs[i] = 1;
+            } else {
+                if (strtolEnd != ntP->end)
+                    pm_asprintf(errorP, "syntax error");
             }
 
-            state.mode = DRAW_MODE_FAN;
-            state.draw = false;
-            state.next = 0;
-
-            ok = true;
-
-            break;
-        default:
-            unrecognized_arg = true;
-        }
-
-        if (unrecognized_arg) {
-            pm_errormsg("error: unrecognized drawing mode in line %lu.",
-                        line->number);
+            if (!*errorP) {
+                if (i < 3) {
+                    if (iArgs[i] < MIN_COORD || iArgs[i] > MAX_COORD)
+                        pm_asprintf(errorP, "coordinates out of bounds");
+                } else {
+                    if (iArgs[i] < MIN_INPUT_W || iArgs[i] > MAX_INPUT_W)
+                        pm_asprintf(errorP,
+                                    "perspective correction factor (w) "
+                                    "out of bounds");
+                }
+            }
         }
 
-        break;
-    case 'a': {
-        uint8_t i;
-        if (!string_is_valid(CMD_SET_ATTRIBS, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
-
-            break;
-        }
+        if (!*errorP) {
+            unsigned int i;
 
-        for (i = 0; i < fbi->num_attribs; i++) {
-            nt = next_token(nt.end);
+            for (i = 0; i < fbiP->num_attribs; ++i) {
+                stateP->v_attribs._[stateP->next][i] = stateP->curr_attribs[i];
+            }
 
-            i_args[i] = strtol(nt.begin, &strtol_end, 10);
+            stateP->v_attribs._[stateP->next][fbiP->num_attribs + 0] =
+                iArgs[2];
+            stateP->v_attribs._[stateP->next][fbiP->num_attribs + 1] =
+                iArgs[3];
 
-            if (*nt.begin == '\0' || strtol_end != nt.end) {
-                pm_errormsg(SYNTAX_ERROR, line->number);
+            stateP->v_xy._[stateP->next][0] = iArgs[0];
+            stateP->v_xy._[stateP->next][1] = iArgs[1];
 
-                must_break_out = true;
+            ++stateP->next;
 
-                break;
+            if (!stateP->draw) {
+                if (stateP->next == 3)
+                    stateP->draw = true;
             }
 
-            if (i_args[i] < 0 || i_args[i] > fbi->maxval) {
-                pm_errormsg("error: argument(s) out of bounds: line %lu.",
-                            line->number);
-
-                must_break_out = true;
+            if (stateP->draw)
+                draw_triangle(stateP->v_xy, stateP->v_attribs, biP, fbiP);
 
-                break;
+            if (stateP->next == 3) {
+                switch(stateP->mode) {
+                case DRAW_MODE_FAN:
+                    stateP->next = 1;
+                    break;
+                case DRAW_MODE_TRIANGLES:
+                    stateP->draw = false;
+                    stateP->next = 0;
+                    break;
+                case DRAW_MODE_STRIP:
+                    stateP->next = 0;
+                    break;
+                default:
+                    stateP->next = 0;
+                }
             }
         }
+    }
+}
 
-        if (must_break_out)
-        {
-            break;
-        }
-
-        for (i = 0; i < fbi->num_attribs; i++) {
-            state.curr_attribs[i] = i_args[i];
-        }
-
-        ok = true;
 
-    } break;
-    case 'v': {
-        uint8_t i;
 
-        if (!string_is_valid(CMD_VERTEX, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
+static void
+processP(Token *            const ntP,
+         framebuffer_info * const fbiP,
+         bool *             const unrecognizedCmdP,
+         const char **      const errorP) {
 
-            break;
-        }
+    if (!stringIsValid(CMD_PRINT, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        for (i = 0; i < 4; i++) {
-            nt = next_token(nt.end);
+        print_framebuffer(fbiP);
 
-            i_args[i] = strtol(nt.begin, &strtol_end, 10);
+        *errorP = NULL;
+    }
+}
 
-            if (*nt.begin == '\0') {
-		if(i != 3) {
-                    pm_errormsg(SYNTAX_ERROR, line->number);
 
-                    must_break_out = true;
 
-                    break;
-                } else {
-                    i_args[i] = 1;
-                }
-            } else {
-                if (strtol_end != nt.end) {
-                    pm_errormsg(SYNTAX_ERROR, line->number);
 
-                    must_break_out = true;
+static void
+processExcl(Token *            const ntP,
+            framebuffer_info * const fbiP,
+            bool *             const unrecognizedCmdP,
+            const char **      const errorP) {
 
-                    break;
-                }
-            }
+    if (ntP->end - ntP->begin > 1)
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-            if (i < 3) {
-                if (i_args[i] < MIN_COORD || i_args[i] > MAX_COORD) {
-                    pm_errormsg(
-                        "error: coordinates out of bounds: line %lu.",
-                        line->number);
+        print_framebuffer(fbiP);
 
-                    must_break_out = true;
+        *errorP = NULL;
+    }
+}
 
-                    break;
-                }
-            } else {
-                if (i_args[i] < MIN_INPUT_W || i_args[i] > MAX_INPUT_W) {
-                    pm_errormsg(
-                        "error: perspective correction factor (w) out of bounds: line %lu.",
-                        line->number);
 
-                    must_break_out = true;
 
-                    break;
-                }
+static void
+clear(Token *            const ntP,
+      framebuffer_info * const fbiP,
+      const char **      const errorP) {
+
+    *ntP = nextToken(ntP->end);
+
+    if (*ntP->begin != '\0') {
+        makeLowercase(*ntP);
+
+        switch(*ntP->begin) {
+        case 'i':
+            if (!stringIsValid("image", ntP->begin, ntP->end))
+                pm_asprintf(errorP, "unrecognized argument");
+            else {
+                clear_framebuffer(true, false, fbiP);
+                *errorP = NULL;
             }
-        }
-
-        if (must_break_out)
-        {
             break;
-        }
-
-        for (i = 0; i < fbi->num_attribs; i++) {
-            state.v_attribs._[state.next][i] = state.curr_attribs[i];
-        }
-
-        state.v_attribs._[state.next][fbi->num_attribs + 0] = i_args[2];
-        state.v_attribs._[state.next][fbi->num_attribs + 1] = i_args[3];
-
-        state.v_xy._[state.next][0] = i_args[0];
-        state.v_xy._[state.next][1] = i_args[1];
-
-        state.next++;
-
-        if (!state.draw) {
-            if (state.next == 3) {
-                state.draw = true;
+        case 'd':
+            if (!stringIsValid("depth", ntP->begin, ntP->end))
+                pm_asprintf(errorP, "unrecognized argument");
+            else {
+                clear_framebuffer(false, true, fbiP);
+                *errorP = NULL;
             }
-        }
-
-        if (state.draw) {
-            draw_triangle(state.v_xy, state.v_attribs, bi, fbi);
-        }
-
-        if (state.next == 3) {
-            switch(state.mode) {
-            case DRAW_MODE_FAN:
-                state.next = 1;
-                break;
-            case DRAW_MODE_TRIANGLES:
-                state.draw = false;
-            case DRAW_MODE_STRIP:
-            default:
-                state.next = 0;
+            break;
+        case 'z':
+            if (ntP->end - ntP->begin > 1)
+                pm_asprintf(errorP, "unrecognized argument");
+            else {
+                clear_framebuffer(false, true, fbiP);
+                *errorP = NULL;
             }
+            break;
+        default:
+            pm_asprintf(errorP, "unrecognized argument");
         }
+    } else {
+        clear_framebuffer(true, true, fbiP);
+        *errorP = NULL;
+    }
+}
 
-        ok = true;
 
-    } break;
-    case 'p':
-        if (!string_is_valid(CMD_PRINT, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
 
-            break;
-        }
-    case '!':
-        if (*nt.begin == '!') {
-            if (nt.end - nt.begin > 1) {
-                unrecognized_cmd = true;
+static void
+processC(Token *            const ntP,
+         framebuffer_info * const fbiP,
+         bool *             const unrecognizedCmdP,
+         const char **      const errorP) {
 
-                break;
-            }
-        }
+    if (!stringIsValid(CMD_CLEAR, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        print_framebuffer(fbi);
+        clear(ntP, fbiP, errorP);
+    }
+}
 
-        ok = true;
 
-        break;
-    case 'c':
-        if (!string_is_valid(CMD_CLEAR, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
 
-            break;
-        }
-    case '*':
-        if (*nt.begin == '*') {
-            if(nt.end - nt.begin > 1) {
-                unrecognized_cmd = true;
+static void
+processAsterisk(Token *            const ntP,
+                framebuffer_info * const fbiP,
+                bool *             const unrecognizedCmdP,
+                const char **      const errorP) {
 
-                break;
-            }
-        }
+    if (ntP->end - ntP->begin > 1)
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        nt = next_token(nt.end);
+        clear(ntP, fbiP, errorP);
+    }
+}
 
-        if (*nt.begin != '\0') {
-            make_lowercase(nt);
 
-            switch(*nt.begin) {
-            case 'i':
-                if (!string_is_valid("image", nt.begin, nt.end)) {
-                    unrecognized_arg = true;
 
-                    break;
-                }
+static void
+processR(Token *                const ntP,
+         state_info *           const stateP,
+         framebuffer_info *     const fbiP,
+         bool *                 const unrecognizedCmdP,
+         long int *             const iArgs,
+         const char **          const errorP) {
 
-                clear_framebuffer(true, false, fbi);
+    if (!stringIsValid(CMD_RESET, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        unsigned int i;
 
-                break;
-            case 'd':
-                if (!string_is_valid("depth", nt.begin, nt.end)) {
-                    unrecognized_arg = true;
+        *unrecognizedCmdP = false;
 
-                    break;
-                }
-            case 'z':
-                if (*nt.begin == 'z') {
-                    if (nt.end - nt.begin > 1) {
-                        unrecognized_arg = true;
+        for (i = 0, *errorP = NULL; i < 2 && !*errorP; ++i) {
+            char * strtolEnd;
 
-                        break;
-                    }
-                }
+            *ntP = nextToken(ntP->end);
 
-                clear_framebuffer(false, true, fbi);
+            iArgs[i] = strtol(ntP->begin, &strtolEnd, 10);
 
-                break;
-            default:
-                unrecognized_arg = true;
-            }
+            if (*ntP->begin == '\0' || ntP->end != strtolEnd)
+                pm_asprintf(errorP, "syntax error");
+        }
 
-            if (unrecognized_arg) {
-                pm_errormsg("error: unrecognized argument: line %lu.",
-                            line->number);
+        if (!*errorP) {
+            if (iArgs[0] < 1 || iArgs[0] > PAM_OVERALL_MAXVAL)
+                pm_asprintf(errorP, "invalid new maxval");
+            else {
+                if (iArgs[1] < 1 || iArgs[1] > MAX_NUM_ATTRIBS)
+                    pm_asprintf(errorP, "invalid new number of generic vertex "
+                                "attributes");
+                else {
+                    *ntP = nextToken(ntP->end);
+
+                    if (*ntP->begin != '\0') {
+                        if (!set_tupletype(ntP->begin,
+                                           fbiP->outpam.tuple_type)) {
+                            pm_message(
+                                "warning: could not set new tuple type; "
+                                "using a null string");
+                            set_tupletype(NULL, fbiP->outpam.tuple_type);
+                        }
+                    } else
+                        set_tupletype(NULL, fbiP->outpam.tuple_type);
+
+                    if (!realloc_image_buffer(iArgs[0], iArgs[1], fbiP)) {
+                        pm_error("Unable to allocate memory for "
+                                 "image buffer");
+                    }
 
-                break;
+                    stateP->next = 0;
+                    stateP->draw = false;
+
+                    clearAttribs(stateP, fbiP->maxval, fbiP->num_attribs);
+                }
             }
-        } else {
-            clear_framebuffer(true, true, fbi);
         }
+    }
+}
 
-        ok = true;
 
-        break;
-    case 'r': {
-        uint8_t i;
 
-        if (!string_is_valid(CMD_RESET, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
+static void
+processQ(Token *                const ntP,
+         bool *                 const unrecognizedCmdP,
+         bool *                 const noMoreCommandsP,
+         const char **          const errorP) {
 
-            break;
-        }
+    if (!stringIsValid(CMD_QUIT, ntP->begin, ntP->end))
+        *unrecognizedCmdP = true;
+    else {
+        *unrecognizedCmdP = false;
 
-        for (i = 0; i < 2; i++) {
-            nt = next_token(nt.end);
+        *noMoreCommandsP = true;
 
-            i_args[i] = strtol(nt.begin, &strtol_end, 10);
+        *errorP = NULL;
+    }
+}
 
-            if (*nt.begin == '\0' || nt.end != strtol_end) {
-                pm_errormsg(SYNTAX_ERROR, line->number);
 
-                must_break_out = true;
 
-                break;
-            }
-        }
+void
+input_process_next_command(Input *                const inputP,
+                           struct boundary_info * const biP,
+                           framebuffer_info *     const fbiP,
+                           bool *                 const noMoreCommandsP) {
+/*----------------------------------------------------------------------------
+  Doesn't necessarily process a command, just the next line of input, which
+  may be empty.
 
-        if (must_break_out) {
-            break;
-        }
+  Return *noMoreCommandsP true iff the next command is a quit command of
+  there is no next command.
+-----------------------------------------------------------------------------*/
+    static state_info state;
 
-        if (i_args[0] < 1 || i_args[0] > PAM_OVERALL_MAXVAL) {
-            pm_errormsg("error: invalid new maxval: line %lu.",
-                        line->number);
+    Token nt;
 
-            break;
-        }
+    long int iArgs[MAX_NUM_ATTRIBS];
+        /* For storing potential integer arguments. */
+    bool unrecognizedCmd;
+        /* Unrecognized command detected */
+    bool noMoreCommands;
+    const char * error;
+        /* Description of problem with the command; NULL if no problem.
+           Meaningful only when 'unrecognizedCmd' is false.
+        */
 
-        if (i_args[1] < 1 || i_args[1] > MAX_NUM_ATTRIBS) {
-            pm_errormsg("error: invalid new number of generic vertex "
-                        "attributes: line %lu.", line->number);
+    if (!state.initialized) {
+        initState(&state);
+        clearAttribs(&state, fbiP->maxval, fbiP->num_attribs);
 
-            break;
-        }
+        state.initialized = true;
+    }
 
-        nt = next_token(nt.end);
+    {
+        int eof;
+        size_t lineLen;
 
-        if (*nt.begin != '\0') {
-            if (!set_tupletype(nt.begin, fbi->outpam.tuple_type)) {
-                pm_message("warning: could not set new tuple type; "
-                           "using a null string: line %lu.",
-                           line->number);
+        pm_getline(stdin, &inputP->buffer, &inputP->length, &eof, &lineLen);
 
-                set_tupletype(NULL, fbi->outpam.tuple_type);
-            }
-        } else {
-            set_tupletype(NULL, fbi->outpam.tuple_type);
+        if (eof) {
+            *noMoreCommandsP = true;
+            return;
         }
+    }
 
-        if (!realloc_image_buffer(i_args[0], i_args[1], fbi)) {
-            pm_errormsg
-                (
-                    "fatal error upon reading line %lu: "
-                    "could not reallocate image buffer -- "
-                    "terminating pamtris.",
-                    line->number
-                    );
+    removeComments(inputP->buffer);
 
-            return 0;
-        }
+    nt = nextToken(inputP->buffer);
 
-        state.next = 0;
-        state.draw = false;
+    makeLowercase(nt);
 
-        clear_attribs(&state, fbi->maxval, fbi->num_attribs);
+    noMoreCommands = false;  /* initial assumption */
 
-    } break;
+    pm_message("command '%s'", nt.begin);
+    switch (nt.begin[0]) {
+    case 'm':
+        processM(&nt, &state, &unrecognizedCmd, &error);
+        break;
+    case 'a':
+        processA(&nt, &state, fbiP, &unrecognizedCmd, iArgs, &error);
+        break;
+    case 'v':
+        processV(&nt, &state, biP, fbiP, &unrecognizedCmd, iArgs, &error);
+        break;
+    case 'p':
+        processP(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case '!':
+        processExcl(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case 'c':
+        processC(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case '*':
+        processAsterisk(&nt, fbiP, &unrecognizedCmd, &error);
+        break;
+    case 'r':
+        processR(&nt, &state, fbiP, &unrecognizedCmd, iArgs, &error);
+        break;
     case 'q':
-        if (!string_is_valid(CMD_QUIT, nt.begin, nt.end)) {
-            unrecognized_cmd = true;
-
-            break;
-        }
-
-        return 0;
+        processQ(&nt, &unrecognizedCmd, &noMoreCommands, &error);
+        break;
     case '\0':
         break;
     default:
-        unrecognized_cmd = true;
+        unrecognizedCmd = true;
     }
 
-    {
-        char const next = *next_token(nt.end).begin;
+    if (!noMoreCommands) {
+        char const next = *nextToken(nt.end).begin;
 
-        if (unrecognized_cmd) {
+        if (unrecognizedCmd) {
             pm_errormsg("error: unrecognized command: line %lu.",
-                        line->number);
-        }
-        else if (ok && next != '\0') {
-            pm_message(WARNING_EXCESS_ARGS, line->number);
+                        inputP->number);
+        } else {
+            if (error) {
+                pm_errormsg("Error in line %lu: %s", inputP->number, error);
+                pm_strfree(error);
+            } else {
+                if (next != '\0')
+                    pm_message(WARNING_EXCESS_ARGS, inputP->number);
+            }
         }
     }
-    line->number++;
+    ++inputP->number;
 
-    return 1;
+    *noMoreCommandsP = noMoreCommands;
 }
 
 
diff --git a/generator/pamtris/input.h b/generator/pamtris/input.h
index 66969bb2..d34de3a1 100644
--- a/generator/pamtris/input.h
+++ b/generator/pamtris/input.h
@@ -6,26 +6,22 @@
 struct boundary_info;
 struct framebuffer_info;
 
-typedef struct input_info {
-/*----------------------------------------------------------------------------
-  Information necessary for the "process_next_command" function.  It must be
-  initialized through "init_input_processor" and freed by
-  "free_input_processor".
------------------------------------------------------------------------------*/
+typedef struct {
     char *   buffer;
     size_t   length;
     uint64_t number;
-} input_info;
+} Input;
 
 void
-init_input_processor(input_info * const ii);
+input_init(Input * const inputP);
 
 void
-free_input_processor(input_info * const ii);
+input_term(Input * const inputP);
 
-int
-process_next_command(input_info *              const ii,
-                     struct boundary_info *    const bdi,
-                     struct framebuffer_info * const fbi);
+void
+input_process_next_command(Input *                   const inputP,
+                           struct boundary_info *    const bdiP,
+                           struct framebuffer_info * const fbiP,
+                           bool *                    const noMoreCommandsP);
 
 #endif
diff --git a/generator/pamtris/pamtris.c b/generator/pamtris/pamtris.c
index d31e07a6..e0becf7a 100644
--- a/generator/pamtris/pamtris.c
+++ b/generator/pamtris/pamtris.c
@@ -131,7 +131,8 @@ main(int argc, const char ** argv) {
 
     framebuffer_info fbi;
     boundary_info bi;
-    input_info ii;
+    Input input;
+    bool no_more_commands;
 
     pm_proginit(&argc, (const char**)argv);
 
@@ -155,11 +156,12 @@ main(int argc, const char ** argv) {
 
     init_boundary_buffer(&bi, fbi.height);
 
-    init_input_processor(&ii);
+    input_init(&input);
 
-    while (process_next_command(&ii, &bi, &fbi));
+    for (no_more_commands = false; !no_more_commands; )
+        input_process_next_command(&input, &bi, &fbi, &no_more_commands);
 
-    free_input_processor(&ii);
+    input_term(&input);
     free_boundary_buffer(&bi);
     free_framebuffer(&fbi);