diff options
-rw-r--r-- | doc/ScintillaHistory.html | 5 | ||||
-rw-r--r-- | include/SciLexer.h | 14 | ||||
-rw-r--r-- | include/Scintilla.iface | 16 | ||||
-rw-r--r-- | lexers/LexHex.cxx | 360 | ||||
-rw-r--r-- | src/Catalogue.cxx | 1 | ||||
-rw-r--r-- | win32/scintilla.mak | 3 |
6 files changed, 399 insertions, 0 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index a1cb40b68..340bcc234 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -463,6 +463,7 @@ </tr><tr> <td>Erik Angelin</td> <td>Yusuf Ramazan Karagöz</td> + <td>Markus Heidelberg</td> </tr> </table> <p> @@ -482,6 +483,10 @@ Released 2 December 2014. </li> <li> + Lexer added for Motorola S-Record files. + <a href="http://sourceforge.net/p/scintilla/feature-requests/1091/">Feature #1091.</a> + </li> + <li> C++ folder allows folding on square brackets '['. <a href="http://sourceforge.net/p/scintilla/feature-requests/1087/">Feature #1087.</a> </li> diff --git a/include/SciLexer.h b/include/SciLexer.h index dc75a98b6..b2539eb91 100644 --- a/include/SciLexer.h +++ b/include/SciLexer.h @@ -129,6 +129,7 @@ #define SCLEX_DMIS 114 #define SCLEX_REGISTRY 115 #define SCLEX_BIBTEX 116 +#define SCLEX_SREC 117 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -1741,6 +1742,19 @@ #define SCE_BIBTEX_PARAMETER 4 #define SCE_BIBTEX_VALUE 5 #define SCE_BIBTEX_COMMENT 6 +#define SCE_SREC_DEFAULT 0 +#define SCE_SREC_RECSTART 1 +#define SCE_SREC_RECTYPE 2 +#define SCE_SREC_BYTECOUNT 3 +#define SCE_SREC_BYTECOUNT_WRONG 4 +#define SCE_SREC_NOADDRESS 5 +#define SCE_SREC_DATAADDRESS 6 +#define SCE_SREC_RECCOUNT 7 +#define SCE_SREC_STARTADDRESS 8 +#define SCE_SREC_DATA_ODD 9 +#define SCE_SREC_DATA_EVEN 10 +#define SCE_SREC_CHECKSUM 11 +#define SCE_SREC_CHECKSUM_WRONG 12 /* --Autogenerated -- end of section automatically generated from Scintilla.iface */ #endif diff --git a/include/Scintilla.iface b/include/Scintilla.iface index ca54c65ee..803028022 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -2719,6 +2719,7 @@ val SCLEX_AS=113 val SCLEX_DMIS=114 val SCLEX_REGISTRY=115 val SCLEX_BIBTEX=116 +val SCLEX_SREC=117 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -4542,6 +4543,21 @@ val SCE_BIBTEX_KEY=3 val SCE_BIBTEX_PARAMETER=4 val SCE_BIBTEX_VALUE=5 val SCE_BIBTEX_COMMENT=6 +# Lexical state for SCLEX_SREC +lex Srec=SCLEX_SREC SCE_SREC_ +val SCE_SREC_DEFAULT=0 +val SCE_SREC_RECSTART=1 +val SCE_SREC_RECTYPE=2 +val SCE_SREC_BYTECOUNT=3 +val SCE_SREC_BYTECOUNT_WRONG=4 +val SCE_SREC_NOADDRESS=5 +val SCE_SREC_DATAADDRESS=6 +val SCE_SREC_RECCOUNT=7 +val SCE_SREC_STARTADDRESS=8 +val SCE_SREC_DATA_ODD=9 +val SCE_SREC_DATA_EVEN=10 +val SCE_SREC_CHECKSUM=11 +val SCE_SREC_CHECKSUM_WRONG=12 # Events diff --git a/lexers/LexHex.cxx b/lexers/LexHex.cxx new file mode 100644 index 000000000..ff4aec3a8 --- /dev/null +++ b/lexers/LexHex.cxx @@ -0,0 +1,360 @@ +// Scintilla source code edit control +/** @file LexHex.cxx + ** Lexer for Motorola S-Record. + ** + ** Written by Markus Heidelberg + **/ +// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +/* + * Motorola S-Record file format + * =============================== + * + * Each record (line) is built as follows: + * + * field size states + * + * +----------+ + * | start | 1 ('S') SCE_SREC_RECSTART + * +----------+ + * | type | 1 SCE_SREC_RECTYPE + * +----------+ + * | count | 2 SCE_SREC_BYTECOUNT, SCE_SREC_BYTECOUNT_WRONG + * +----------+ + * | address | 4/6/8 SCE_SREC_NOADDRESS, SCE_SREC_DATAADDRESS, SCE_SREC_RECCOUNT, SCE_SREC_STARTADDRESS + * +----------+ + * | data | 0..500 SCE_SREC_DATA_ODD, SCE_SREC_DATA_EVEN + * +----------+ + * | checksum | 2 SCE_SREC_CHECKSUM, SCE_SREC_CHECKSUM_WRONG + * +----------+ + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "LexerModule.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +// prototypes for general helper functions +static inline bool IsNewline(const int ch); +static int GetHexaChar(char hd1, char hd2); +static int GetHexaChar(unsigned int pos, Accessor &styler); +static bool ForwardWithinLine(StyleContext &sc, int nb = 1); + +// prototypes for file format specific helper functions +static unsigned int GetSrecRecStartPosition(unsigned int pos, Accessor &styler); +static int GetSrecByteCount(unsigned int recStartPos, Accessor &styler); +static int CountSrecByteCount(unsigned int recStartPos, Accessor &styler); +static int GetSrecAddressFieldSize(unsigned int recStartPos, Accessor &styler); +static int GetSrecAddressFieldType(unsigned int recStartPos, Accessor &styler); +static int GetSrecChecksum(unsigned int recStartPos, Accessor &styler); +static int CalcSrecChecksum(unsigned int recStartPos, Accessor &styler); + +static inline bool IsNewline(const int ch) +{ + return (ch == '\n' || ch == '\r'); +} + +static int GetHexaChar(char hd1, char hd2) +{ + int hexValue = 0; + + if (hd1 >= '0' && hd1 <= '9') { + hexValue += 16 * (hd1 - '0'); + } else if (hd1 >= 'A' && hd1 <= 'F') { + hexValue += 16 * (hd1 - 'A' + 10); + } else if (hd1 >= 'a' && hd1 <= 'f') { + hexValue += 16 * (hd1 - 'a' + 10); + } else { + return -1; + } + + if (hd2 >= '0' && hd2 <= '9') { + hexValue += hd2 - '0'; + } else if (hd2 >= 'A' && hd2 <= 'F') { + hexValue += hd2 - 'A' + 10; + } else if (hd2 >= 'a' && hd2 <= 'f') { + hexValue += hd2 - 'a' + 10; + } else { + return -1; + } + + return hexValue; +} + +static int GetHexaChar(unsigned int pos, Accessor &styler) +{ + char highNibble, lowNibble; + + highNibble = styler.SafeGetCharAt(pos); + lowNibble = styler.SafeGetCharAt(pos + 1); + + return GetHexaChar(highNibble, lowNibble); +} + +// Forward <nb> characters, but abort (and return false) if hitting the line +// end. Return true if forwarding within the line was possible. +// Avoids influence on highlighting of the subsequent line if the current line +// is malformed (too short). +static bool ForwardWithinLine(StyleContext &sc, int nb) +{ + for (int i = 0; i < nb; i++) { + if (sc.atLineEnd) { + // line is too short + sc.SetState(SCE_SREC_DEFAULT); + sc.Forward(); + return false; + } else { + sc.Forward(); + } + } + + return true; +} + +// Get the position of the record "start" field (first character in line) in +// the record around position <pos>. +static unsigned int GetSrecRecStartPosition(unsigned int pos, Accessor &styler) +{ + while (styler.SafeGetCharAt(pos) != 'S') { + pos--; + } + + return pos; +} + +// Get the value of the "byte count" field, it counts the number of bytes in +// the subsequent fields ("address", "data" and "checksum" fields). +static int GetSrecByteCount(unsigned int recStartPos, Accessor &styler) +{ + int val; + + val = GetHexaChar(recStartPos + 2, styler); + if (val < 0) { + val = 0; + } + + return val; +} + +// Count the number of digit pairs in this record from "address" field to end +// of line. Has to be equal to the "byte count" field value. +static int CountSrecByteCount(unsigned int recStartPos, Accessor &styler) +{ + unsigned int pos; + + // start counting at "address" field + pos = recStartPos + 4; + + while (!IsNewline(styler.SafeGetCharAt(pos, '\n'))) { + pos++; + } + + // divide by 2 because of digit pairs + // Round up if odd (digit pair incomplete), this way the byte count is + // considered to be valid if the checksum is incomplete. + return ((pos - (recStartPos + 4)) + 1) / 2; +} + +// Get the size of the "address" field. +static int GetSrecAddressFieldSize(unsigned int recStartPos, Accessor &styler) +{ + switch (styler.SafeGetCharAt(recStartPos + 1)) { + case '0': + case '1': + case '5': + case '9': + return 2; // 16 bit + + case '2': + case '6': + case '8': + return 3; // 24 bit + + case '3': + case '7': + return 4; // 32 bit + + default: + return 0; + } +} + +// Get the type of the "address" field content. +static int GetSrecAddressFieldType(unsigned int recStartPos, Accessor &styler) +{ + switch (styler.SafeGetCharAt(recStartPos + 1)) { + case '0': + return SCE_SREC_NOADDRESS; + + case '1': + case '2': + case '3': + return SCE_SREC_DATAADDRESS; + + case '5': + case '6': + return SCE_SREC_RECCOUNT; + + case '7': + case '8': + case '9': + return SCE_SREC_STARTADDRESS; + + default: + return SCE_SREC_DEFAULT; + } +} + +// Get the value of the "checksum" field. +static int GetSrecChecksum(unsigned int recStartPos, Accessor &styler) +{ + int byteCount; + + byteCount = GetSrecByteCount(recStartPos, styler); + + return GetHexaChar(recStartPos + 2 + byteCount * 2, styler); +} + +// Calculate the checksum of the record. +static int CalcSrecChecksum(unsigned int recStartPos, Accessor &styler) +{ + int byteCount; + unsigned int cs = 0; + + byteCount = GetSrecByteCount(recStartPos, styler); + + // sum over "byte count", "address" and "data" fields + for (unsigned int pos = recStartPos + 2; pos < recStartPos + 2 + byteCount * 2; pos += 2) { + int val = GetHexaChar(pos, styler); + + if (val < 0) { + return val; + } + + cs += val; + } + + // low byte of one's complement + return (~cs) & 0xFF; +} + +static void ColouriseSrecDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler) +{ + StyleContext sc(startPos, length, initStyle, styler); + + while (sc.More()) { + unsigned int recStartPos; + int byteCount, addrFieldSize, addrFieldType, dataFieldSize; + int cs1, cs2; + + switch (sc.state) { + case SCE_SREC_DEFAULT: + if (sc.atLineStart && sc.Match('S')) { + sc.SetState(SCE_SREC_RECSTART); + } + ForwardWithinLine(sc); + break; + + case SCE_SREC_RECSTART: + sc.SetState(SCE_SREC_RECTYPE); + ForwardWithinLine(sc); + break; + + case SCE_SREC_RECTYPE: + recStartPos = sc.currentPos - 2; + byteCount = GetSrecByteCount(recStartPos, styler); + + if (byteCount == CountSrecByteCount(recStartPos, styler)) { + sc.SetState(SCE_SREC_BYTECOUNT); + } else { + sc.SetState(SCE_SREC_BYTECOUNT_WRONG); + } + + ForwardWithinLine(sc, 2); + break; + + case SCE_SREC_BYTECOUNT: + case SCE_SREC_BYTECOUNT_WRONG: + recStartPos = sc.currentPos - 4; + addrFieldSize = GetSrecAddressFieldSize(recStartPos, styler); + addrFieldType = GetSrecAddressFieldType(recStartPos, styler); + + if (addrFieldSize > 0) { + sc.SetState(addrFieldType); + ForwardWithinLine(sc, addrFieldSize * 2); + } else { + // malformed + sc.SetState(SCE_SREC_DEFAULT); + ForwardWithinLine(sc); + } + break; + + case SCE_SREC_NOADDRESS: + case SCE_SREC_DATAADDRESS: + case SCE_SREC_RECCOUNT: + case SCE_SREC_STARTADDRESS: + recStartPos = GetSrecRecStartPosition(sc.currentPos, styler); + byteCount = GetSrecByteCount(recStartPos, styler); + addrFieldSize = GetSrecAddressFieldSize(recStartPos, styler); + dataFieldSize = byteCount - addrFieldSize - 1; // -1 for checksum field + + sc.SetState(SCE_SREC_DATA_ODD); + + for (int i = 0; i < dataFieldSize * 2; i++) { + if ((i & 0x3) == 0) { + sc.SetState(SCE_SREC_DATA_ODD); + } else if ((i & 0x3) == 2) { + sc.SetState(SCE_SREC_DATA_EVEN); + } + + if (!ForwardWithinLine(sc)) { + break; + } + } + break; + + case SCE_SREC_DATA_ODD: + case SCE_SREC_DATA_EVEN: + recStartPos = GetSrecRecStartPosition(sc.currentPos, styler); + cs1 = CalcSrecChecksum(recStartPos, styler); + cs2 = GetSrecChecksum(recStartPos, styler); + + if (cs1 != cs2 || cs1 < 0 || cs2 < 0) { + sc.SetState(SCE_SREC_CHECKSUM_WRONG); + } else { + sc.SetState(SCE_SREC_CHECKSUM); + } + + ForwardWithinLine(sc, 2); + break; + + case SCE_SREC_CHECKSUM: + case SCE_SREC_CHECKSUM_WRONG: + // record finished + sc.SetState(SCE_SREC_DEFAULT); + ForwardWithinLine(sc); + break; + } + } + sc.Complete(); +} + +LexerModule lmSrec(SCLEX_SREC, ColouriseSrecDoc, "srec", 0, NULL); diff --git a/src/Catalogue.cxx b/src/Catalogue.cxx index 3fd006f7a..e2377e14c 100644 --- a/src/Catalogue.cxx +++ b/src/Catalogue.cxx @@ -174,6 +174,7 @@ int Scintilla_LinkLexers() { LINK_LEXER(lmSpecman); LINK_LEXER(lmSpice); LINK_LEXER(lmSQL); + LINK_LEXER(lmSrec); LINK_LEXER(lmSTTXT); LINK_LEXER(lmTACL); LINK_LEXER(lmTADS3); diff --git a/win32/scintilla.mak b/win32/scintilla.mak index 43679cbc7..e1c5277bc 100644 --- a/win32/scintilla.mak +++ b/win32/scintilla.mak @@ -136,6 +136,7 @@ LEXOBJS=\ $(DIR_O)\LexGAP.obj \ $(DIR_O)\LexGui4Cli.obj \ $(DIR_O)\LexHaskell.obj \ + $(DIR_O)\LexHex.obj \ $(DIR_O)\LexHTML.obj \ $(DIR_O)\LexInno.obj \ $(DIR_O)\LexKix.obj \ @@ -530,6 +531,8 @@ $(DIR_O)\LexGui4Cli.obj: ..\lexers\LexGui4Cli.cxx $(LEX_HEADERS) $(DIR_O)\LexHaskell.obj: ..\lexers\LexHaskell.cxx $(LEX_HEADERS) +$(DIR_O)\LexHex.obj: ..\lexers\LexHex.cxx $(LEX_HEADERS) + $(DIR_O)\LexHTML.obj: ..\lexers\LexHTML.cxx $(LEX_HEADERS) $(DIR_O)\LexInno.obj: ..\lexers\LexInno.cxx $(LEX_HEADERS) |