From 99fb1bc3e8953170440a7b9dd18f965fa632f5bb Mon Sep 17 00:00:00 2001
From: C-o-r-E <can.of.tuna@gmail.com>
Date: Thu, 5 Mar 2015 15:22:37 -0500
Subject: [PATCH 1/2] Attempt to resolve #1568 and add basic escape character
 support

---
 Marlin/Marlin_main.cpp | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 79416850be..b6a1ee2b6e 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -730,7 +730,6 @@ void get_command()
     serial_char = MYSERIAL.read();
     if(serial_char == '\n' ||
        serial_char == '\r' ||
-       (serial_char == ':' && comment_mode == false) ||
        serial_count >= (MAX_CMD_SIZE - 1) )
     {
       if(!serial_count) { //if empty line
@@ -739,7 +738,6 @@ void get_command()
       }
       cmdbuffer[bufindw][serial_count] = 0; //terminate string
       if(!comment_mode){
-        comment_mode = false; //for new command
         fromsd[bufindw] = false;
         if(strchr(cmdbuffer[bufindw], 'N') != NULL)
         {
@@ -823,10 +821,19 @@ void get_command()
       }
       serial_count = 0; //clear buffer
     }
-    else
-    {
-      if(serial_char == ';') comment_mode = true;
-      if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
+    else if(serial_char == '\\') {  //Handle escapes
+       
+        if(MYSERIAL.available() > 0  && buflen < BUFSIZE) {
+            // if we have one more character, copy it over
+            MYSERIAL.read();
+            cmdbuffer[bufindw][serial_count++] = serial_char;
+        }
+
+        //otherwise do nothing        
+    }
+    else { // its not a newline, carriage return or escape char
+        if(serial_char == ';') comment_mode = true;
+        if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
     }
   }
   #ifdef SDSUPPORT

From 63b62d8d4ebbd700758771c0098e100cc40dd17a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= <osd@foosel.net>
Date: Thu, 5 Mar 2015 23:30:34 +0100
Subject: [PATCH 2/2] Fixed in-line comments and escaping

  * "G1 X1 ; test" was not executing "G1 X1" due to never leaving comment mode.
  * "M117 Hello \;)" printed "Hello \" to the display due to not replacing serial_char properly.

Tested with the following commands:
    * M117 Hello ; test => displays "Hello" on display, ignores "test"
    * G1 X1 ; foo => moves 1mm in X, ignores "foo"
    * ; test => completely ignored, not even acknowledged
    * M117 Hello \;) => displays "Hello ;)" on display
    * M117 Hello \\;) => displays "Hello \" on display, ignores ")"
---
 Documentation/GCodes.md |  22 ++++++
 Marlin/Marlin_main.cpp  | 145 ++++++++++++++++++++--------------------
 2 files changed, 96 insertions(+), 71 deletions(-)

diff --git a/Documentation/GCodes.md b/Documentation/GCodes.md
index 253fb7fc81..fde8435932 100644
--- a/Documentation/GCodes.md
+++ b/Documentation/GCodes.md
@@ -101,3 +101,25 @@
 *  M908 - Control digital trimpot directly.
 *  M928 - Start SD logging (M928 filename.g) - ended by M29
 *  M999 - Restart after being stopped by error
+
+# Comments
+
+Comments start at a `;` (semicolon) and end with the end of the line:
+
+    N3 T0*57 ; This is a comment
+    N4 G92 E0*67
+    ; So is this
+    N5 G28*22
+
+(example taken from the [RepRap wiki](http://reprap.org/wiki/Gcode#Comments))
+
+If you need to use a literal `;` somewhere (for example within `M117`), you can escape semicolons with a `\`
+(backslash):
+
+     M117 Hello \;)
+
+`\` can also be used to escape `\` itself, if you need a literal `\` in front of a `;`:
+
+    M117 backslash: \\;and a comment
+
+Please note that hosts should strip any comments before sending GCODE to the printer in order to save bandwidth.
\ No newline at end of file
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index b6a1ee2b6e..c759a78c0c 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -732,100 +732,103 @@ void get_command()
        serial_char == '\r' ||
        serial_count >= (MAX_CMD_SIZE - 1) )
     {
-      if(!serial_count) { //if empty line
-        comment_mode = false; //for new command
+      // end of line == end of comment
+      comment_mode = false;
+
+      if(!serial_count) {
+        // short cut for empty lines
         return;
       }
       cmdbuffer[bufindw][serial_count] = 0; //terminate string
-      if(!comment_mode){
-        fromsd[bufindw] = false;
-        if(strchr(cmdbuffer[bufindw], 'N') != NULL)
+
+      fromsd[bufindw] = false;
+      if(strchr(cmdbuffer[bufindw], 'N') != NULL)
+      {
+        strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
+        gcode_N = (strtol(strchr_pointer + 1, NULL, 10));
+        if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer[bufindw], PSTR("M110")) == NULL) ) {
+          SERIAL_ERROR_START;
+          SERIAL_ERRORPGM(MSG_ERR_LINE_NO);
+          SERIAL_ERRORLN(gcode_LastN);
+          //Serial.println(gcode_N);
+          FlushSerialRequestResend();
+          serial_count = 0;
+          return;
+        }
+
+        if(strchr(cmdbuffer[bufindw], '*') != NULL)
         {
-          strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
-          gcode_N = (strtol(strchr_pointer + 1, NULL, 10));
-          if(gcode_N != gcode_LastN+1 && (strstr_P(cmdbuffer[bufindw], PSTR("M110")) == NULL) ) {
-            SERIAL_ERROR_START;
-            SERIAL_ERRORPGM(MSG_ERR_LINE_NO);
-            SERIAL_ERRORLN(gcode_LastN);
-            //Serial.println(gcode_N);
-            FlushSerialRequestResend();
-            serial_count = 0;
-            return;
-          }
+          byte checksum = 0;
+          byte count = 0;
+          while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
+          strchr_pointer = strchr(cmdbuffer[bufindw], '*');
 
-          if(strchr(cmdbuffer[bufindw], '*') != NULL)
-          {
-            byte checksum = 0;
-            byte count = 0;
-            while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
-            strchr_pointer = strchr(cmdbuffer[bufindw], '*');
-
-            if( (int)(strtod(strchr_pointer + 1, NULL)) != checksum) {
-              SERIAL_ERROR_START;
-              SERIAL_ERRORPGM(MSG_ERR_CHECKSUM_MISMATCH);
-              SERIAL_ERRORLN(gcode_LastN);
-              FlushSerialRequestResend();
-              serial_count = 0;
-              return;
-            }
-            //if no errors, continue parsing
-          }
-          else
-          {
+          if( (int)(strtod(strchr_pointer + 1, NULL)) != checksum) {
             SERIAL_ERROR_START;
-            SERIAL_ERRORPGM(MSG_ERR_NO_CHECKSUM);
+            SERIAL_ERRORPGM(MSG_ERR_CHECKSUM_MISMATCH);
             SERIAL_ERRORLN(gcode_LastN);
             FlushSerialRequestResend();
             serial_count = 0;
             return;
           }
-
-          gcode_LastN = gcode_N;
           //if no errors, continue parsing
         }
-        else  // if we don't receive 'N' but still see '*'
+        else
         {
-          if((strchr(cmdbuffer[bufindw], '*') != NULL))
-          {
-            SERIAL_ERROR_START;
-            SERIAL_ERRORPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
-            SERIAL_ERRORLN(gcode_LastN);
-            serial_count = 0;
-            return;
-          }
-        }
-        if((strchr(cmdbuffer[bufindw], 'G') != NULL)){
-          strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
-          switch((int)((strtod(strchr_pointer + 1, NULL)))){
-          case 0:
-          case 1:
-          case 2:
-          case 3:
-            if (Stopped == true) {
-              SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
-              LCD_MESSAGEPGM(MSG_STOPPED);
-            }
-            break;
-          default:
-            break;
-          }
-
+          SERIAL_ERROR_START;
+          SERIAL_ERRORPGM(MSG_ERR_NO_CHECKSUM);
+          SERIAL_ERRORLN(gcode_LastN);
+          FlushSerialRequestResend();
+          serial_count = 0;
+          return;
         }
 
-        //If command was e-stop process now
-        if(strcmp(cmdbuffer[bufindw], "M112") == 0)
-          kill();
-        
-        bufindw = (bufindw + 1)%BUFSIZE;
-        buflen += 1;
+        gcode_LastN = gcode_N;
+        //if no errors, continue parsing
       }
+      else  // if we don't receive 'N' but still see '*'
+      {
+        if((strchr(cmdbuffer[bufindw], '*') != NULL))
+        {
+          SERIAL_ERROR_START;
+          SERIAL_ERRORPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
+          SERIAL_ERRORLN(gcode_LastN);
+          serial_count = 0;
+          return;
+        }
+      }
+      if((strchr(cmdbuffer[bufindw], 'G') != NULL)){
+        strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
+        switch((int)((strtod(strchr_pointer + 1, NULL)))){
+        case 0:
+        case 1:
+        case 2:
+        case 3:
+          if (Stopped == true) {
+            SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
+            LCD_MESSAGEPGM(MSG_STOPPED);
+          }
+          break;
+        default:
+          break;
+        }
+
+      }
+
+      //If command was e-stop process now
+      if(strcmp(cmdbuffer[bufindw], "M112") == 0)
+        kill();
+
+      bufindw = (bufindw + 1)%BUFSIZE;
+      buflen += 1;
+
       serial_count = 0; //clear buffer
     }
     else if(serial_char == '\\') {  //Handle escapes
        
         if(MYSERIAL.available() > 0  && buflen < BUFSIZE) {
             // if we have one more character, copy it over
-            MYSERIAL.read();
+            serial_char = MYSERIAL.read();
             cmdbuffer[bufindw][serial_count++] = serial_char;
         }