<commit_before>// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and Javascript.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsOKBeforeRE(const int ch) {
	return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsADoxygenChar(const int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
		    ch == '\\' || ch == '&' || ch == '<' ||
			ch == '>' || ch == '#' || ch == '{' ||
			ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsStateComment(const int state) {
	return ((state == SCE_C_COMMENT) ||
		      (state == SCE_C_COMMENTLINE) ||
		      (state == SCE_C_COMMENTDOC) ||
		      (state == SCE_C_COMMENTDOCKEYWORD) ||
		      (state == SCE_C_COMMENTDOCKEYWORDERROR));
}

static inline bool IsStateString(const int state) {
	return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];

	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;

	// Do not leak onto next line
	if (initStyle == SCE_C_STRINGEOL)
		initStyle = SCE_C_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;
	bool lastWordWasUUID = false;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
			// Prevent SCE_C_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_C_STRING);
		}

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.Match("\\\n")) {
				sc.Forward();
				continue;
			}
			if (sc.Match("\\\r\n")) {
				sc.Forward();
				sc.Forward();
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_C_OPERATOR) {
			sc.SetState(SCE_C_DEFAULT);
		} else if (sc.state == SCE_C_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					lastWordWasUUID = strcmp(s, "uuid") == 0;
					sc.ChangeState(SCE_C_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_C_WORD2);
				}
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_PREPROCESSOR) {
			if (stylingWithinPreprocessor) {
				if (IsASpace(sc.ch)) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else {
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_COMMENT) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_COMMENTDOC) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '@' || sc.ch == '\\') {
				sc.SetState(SCE_C_COMMENTDOCKEYWORD);
			}
		} else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
			if (sc.Match('*', '/')) {
				sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (!IsADoxygenChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
					sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				}
				sc.SetState(SCE_C_COMMENTDOC);
			}
		} else if (sc.state == SCE_C_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_CHARACTER) {
			if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			} else if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_REGEX) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '\\') {
				// Gobble up the quoted character
				if (sc.chNext == '\\' || sc.chNext == '/') {
					sc.Forward();
				}
			}
		} else if (sc.state == SCE_C_VERBATIM) {
			if (sc.ch == '\"') {
				if (sc.chNext == '\"') {
					sc.Forward();
				} else {
					sc.ForwardSetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_UUID) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
				sc.SetState(SCE_C_DEFAULT);
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_C_DEFAULT) {
			if (sc.Match('@', '\"')) {
				sc.SetState(SCE_C_VERBATIM);
				sc.Forward();
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_NUMBER);
				}
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_IDENTIFIER);
				}
			} else if (sc.Match('/', '*')) {
				if (sc.Match("/**") || sc.Match("/*!")) {	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTDOC);
				} else {
					sc.SetState(SCE_C_COMMENT);
				}
				sc.Forward();	// Eat the * so it isn't used for the end of the comment
			} else if (sc.Match('/', '/')) {
				if (sc.Match("///") || sc.Match("//!"))	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTLINEDOC);
				else
					sc.SetState(SCE_C_COMMENTLINE);
			} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
				sc.SetState(SCE_C_REGEX);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_C_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_C_CHARACTER);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_C_PREPROCESSOR);
				// Skip whitespace between # and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else if (isoperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_C_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
			lastWordWasUUID = false;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return style == SCE_C_COMMENT ||
		style == SCE_C_COMMENTDOC ||
		style == SCE_C_COMMENTDOCKEYWORD ||
		style == SCE_C_COMMENTDOCKEYWORDERROR;
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelCurrent++;
			} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelCurrent--;
			}
		}
		if (foldComment && (style == SCE_C_COMMENTLINE)) {
			if ((ch == '/') && (chNext == '/')) {
				char chNext2 = styler.SafeGetCharAt(i + 2);
				if (chNext2 == '{') {
					levelCurrent++;
				} else if (chNext2 == '}') {
					levelCurrent--;
				}
			}
		}
		if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
			if (ch == '#') {
				unsigned int j=i+1;
				while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
					j++;
				}
				if (styler.Match(j, "region") || styler.Match(j, "if")) {
					levelCurrent++;
				} else if (styler.Match(j, "end")) {
					levelCurrent--;
				}
			}
		}
		if (style == SCE_C_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cppWordLists[] = {
	"Primary keywords and identifiers",
	"Secondary keywords and identifiers",
	"Documentation comment keywords",
	0,
};

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc, cppWordLists);
<commit_msg>Patch from Philippe to handling line continuation to suit Macintosh format files.<commit_after>// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and Javascript.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsOKBeforeRE(const int ch) {
	return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsADoxygenChar(const int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
		    ch == '\\' || ch == '&' || ch == '<' ||
			ch == '>' || ch == '#' || ch == '{' ||
			ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsStateComment(const int state) {
	return ((state == SCE_C_COMMENT) ||
		      (state == SCE_C_COMMENTLINE) ||
		      (state == SCE_C_COMMENTDOC) ||
		      (state == SCE_C_COMMENTDOCKEYWORD) ||
		      (state == SCE_C_COMMENTDOCKEYWORDERROR));
}

static inline bool IsStateString(const int state) {
	return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];

	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;

	// Do not leak onto next line
	if (initStyle == SCE_C_STRINGEOL)
		initStyle = SCE_C_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;
	bool lastWordWasUUID = false;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
			// Prevent SCE_C_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_C_STRING);
		}

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_C_OPERATOR) {
			sc.SetState(SCE_C_DEFAULT);
		} else if (sc.state == SCE_C_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					lastWordWasUUID = strcmp(s, "uuid") == 0;
					sc.ChangeState(SCE_C_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_C_WORD2);
				}
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_PREPROCESSOR) {
			if (stylingWithinPreprocessor) {
				if (IsASpace(sc.ch)) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else {
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_COMMENT) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_COMMENTDOC) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '@' || sc.ch == '\\') {
				sc.SetState(SCE_C_COMMENTDOCKEYWORD);
			}
		} else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
			if (sc.Match('*', '/')) {
				sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (!IsADoxygenChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
					sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				}
				sc.SetState(SCE_C_COMMENTDOC);
			}
		} else if (sc.state == SCE_C_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_CHARACTER) {
			if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			} else if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_REGEX) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '\\') {
				// Gobble up the quoted character
				if (sc.chNext == '\\' || sc.chNext == '/') {
					sc.Forward();
				}
			}
		} else if (sc.state == SCE_C_VERBATIM) {
			if (sc.ch == '\"') {
				if (sc.chNext == '\"') {
					sc.Forward();
				} else {
					sc.ForwardSetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_UUID) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
				sc.SetState(SCE_C_DEFAULT);
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_C_DEFAULT) {
			if (sc.Match('@', '\"')) {
				sc.SetState(SCE_C_VERBATIM);
				sc.Forward();
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_NUMBER);
				}
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_IDENTIFIER);
				}
			} else if (sc.Match('/', '*')) {
				if (sc.Match("/**") || sc.Match("/*!")) {	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTDOC);
				} else {
					sc.SetState(SCE_C_COMMENT);
				}
				sc.Forward();	// Eat the * so it isn't used for the end of the comment
			} else if (sc.Match('/', '/')) {
				if (sc.Match("///") || sc.Match("//!"))	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTLINEDOC);
				else
					sc.SetState(SCE_C_COMMENTLINE);
			} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
				sc.SetState(SCE_C_REGEX);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_C_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_C_CHARACTER);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_C_PREPROCESSOR);
				// Skip whitespace between # and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else if (isoperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_C_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
			lastWordWasUUID = false;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return style == SCE_C_COMMENT ||
		style == SCE_C_COMMENTDOC ||
		style == SCE_C_COMMENTDOCKEYWORD ||
		style == SCE_C_COMMENTDOCKEYWORDERROR;
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelCurrent++;
			} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelCurrent--;
			}
		}
		if (foldComment && (style == SCE_C_COMMENTLINE)) {
			if ((ch == '/') && (chNext == '/')) {
				char chNext2 = styler.SafeGetCharAt(i + 2);
				if (chNext2 == '{') {
					levelCurrent++;
				} else if (chNext2 == '}') {
					levelCurrent--;
				}
			}
		}
		if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
			if (ch == '#') {
				unsigned int j=i+1;
				while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
					j++;
				}
				if (styler.Match(j, "region") || styler.Match(j, "if")) {
					levelCurrent++;
				} else if (styler.Match(j, "end")) {
					levelCurrent--;
				}
			}
		}
		if (style == SCE_C_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cppWordLists[] = {
	"Primary keywords and identifiers",
	"Secondary keywords and identifiers",
	"Documentation comment keywords",
	0,
};

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc, cppWordLists);
<|endoftext|>


<commit_before>#include <iostream>
#include <cmath>
#include <fstream>
#include <sstream>
#include <cassert>
#include <iomanip>
#include "private_config.h"

using namespace std;

void
addTime(ardu_clock_t &t, int ticks) {
    t._ticks += ticks;
    while (t._ticks > TICKS_PER_SECOND) {
        t._seconds += 1;
        t._ticks -= TICKS_PER_SECOND;
    }
}

void
print_clock(string n, ardu_clock_t t){
    ardu->_debug << n << " " << t._seconds << "." << setw(FIELD_WIDTH) << setfill('0') << t._ticks << "\n";
}

Arduino::Arduino() {
    _log.exceptions ( ifstream::failbit | ifstream::badbit );
    _debug.exceptions ( ifstream::failbit | ifstream::badbit );

    _log.open("dispatch.log", fstream::out | fstream::trunc);
    _debug.open("debug.log",  fstream::out | fstream::trunc);
    cout << "Setting up the Arduino\n";

    _ticks = 0 ;
    _total_ticks = 0;
    _scenario_length._seconds = 0;
    _scenario_length._ticks = 0;
    _registered_identifers = "";
}

Arduino::~Arduino() {
    if (_log.is_open()) {
        _log << "\n\n";
        _log.close();
    }
    if (_debug.is_open()) {
        _debug << "\n\n";
        _debug.close();
    }
}

void
Arduino::configurePin(uint8_t pin_id, uint8_t mode) {
    map<int, Pin*>::iterator it;
    it = _pins.find(pin_id);

    if (it != _pins.end()) {
        _pins[pin_id]->_mode = mode;
        _debug << "Configuring Pin " << (int)pin_id << " to mode: " << (int)mode <<  "\n";
    }
    else {
        _debug << "Error, pin configured that is not registed\n";
    }
}

bool
Arduino::addInputFile(char *name) {
    ifstream ifile;
    bool header_parsed = false;

    ifile.open(name, ifstream::in);

    while (ifile.good()) {
        string line;
        getline(ifile, line);
        if (line.compare("---") == 0) {
            header_parsed = true;
            continue;
        }
        size_t found = line.find(" ");

        if (found != string::npos) {
            string word = line.substr(0, found);
            if (header_parsed) {
                _debug << "Scanning signals\n";
                registerSignal(word, line);
            }
            else {
                _debug << "Scanning Header\n";
                scanHeaderChunk(word, line);
            }
        }
    }

    ifile.close();

    _debug << "done parsing file\n";
    return true;
}

void
Arduino::runScenario() {
    _timer._seconds = 0;
    _timer._ticks   = 0;
    setup();
    _debug << "Attempting to run the Scenario\n\n";

    print_clock("Scenario Length: ", _scenario_length);
    print_clock("Runtime Timer:", _timer);
    while (!((_timer._seconds > _scenario_length._seconds) || (_timer._seconds == _scenario_length._seconds && _timer._ticks >= _scenario_length._ticks))) {
        loop();
        addTicks(1);
        updatePinState();
    }
    print_clock("Scenario Length: ", _scenario_length);
    print_clock("Runtime Timer:", _timer);

    cout << "--------------------------\n";
}

void
Arduino::addTicks(uint64_t length) {
    _timer._ticks += length;
    if (_timer._ticks > TICKS_PER_SECOND) {
        _timer._seconds++;
        _timer._ticks -= TICKS_PER_SECOND;
    }
}

void
Arduino::updatePinState() {
    // Report Changes in State
    map<int, Pin*>::iterator it;
    for (it = _pins.begin(); it != _pins.end(); it++) {
        it->second->setState(_timer);
    }
}

/*
 * Analog Reads take 100 ms
 * Digital Reads 58 cycles
 */
int
Arduino::getPin(uint8_t pin_id) {
    if (_pins.find(pin_id) == _pins.end())
        return LOW;
    else {
        if (_pins[pin_id]->_val_type == VT_SERIAL) {
            return LOW;
        }
        else if (_pins[pin_id]->_val_type == VT_DIGITAL) {
            addTicks(58);
            return _pins[pin_id]->_state;
        }
        else if (_pins[pin_id]->_val_type == VT_ANALOG) {
            addTicks(MS2T(100));
            return _pins[pin_id]->_state;
        }
        else
            return LOW;
    }
}

void
Arduino::setPin(uint8_t pin_id, uint8_t val) {
    if (_pins[pin_id]->_state != val) {
        _pins[pin_id]->_state = val;
        _pins[pin_id]->_flags &= 0x1;
        cout << timestamp() << "\nUpdating value for: " << static_cast<int>(pin_id) << " " << static_cast<int>(val) << "\n";
    }
}

void
Arduino::dispatchSignal(const char *signal_id) {
    int ticks = _pins[_mapping[signal_id]]->process();

    _timer._ticks += ticks;
    while (_timer._ticks > TICKS_PER_SECOND) {
        _timer._seconds += 1;
        _timer._ticks -= TICKS_PER_SECOND;
    }

    updatePinState();
    _log << "Dispatching signal " << signal_id << " for " << _mapping[signal_id] << " a " << ticks << "\n";
}

string
Arduino::timestamp() {
    ostringstream result(ostringstream::out);
    result << static_cast<int>(_timer._seconds) << "s " << static_cast<int>(_timer._ticks) << "t";
    return result.str();
}

void
Arduino::scanHeaderChunk(string identifier, string line) {
    if (identifier == "length:") {
        double run_time;
        istringstream is;

        is.str(line.substr(identifier.length(), line.length() - identifier.length()));
        is >> run_time;

        cout << "Configuration parsed runtime of " << run_time << "\n";
        _scenario_length._seconds = (int)run_time;
        _scenario_length._ticks = (run_time - floor(run_time)) * TICKS_PER_SECOND;
    }
    else if (identifier == "identifiers:") {
        _registered_identifers = line.substr(identifier.length(), line.length() - identifier.length());
    }
    else if (identifier == "#") {
        // this is a comment, do nothing with this line
    }
    else {
        cout << "Unrecognized header configuration name \"" << identifier << "\"\n";
    }
}

void
Arduino::registerSignal(string identifer, string line) {
    Pin *p = NULL;
    int pin_id = -1;
    string name = "";
    if (identifer == "det") {
        p = new DetPin();
    }
    else if (identifer == "uni") {
        p = new UniPin();
    }
    else if (identifer == "exp") {
        p = new ExpPin();
    }
    else {
        cout << "Bad configuration line \"" << line << "\"\n";
        exit(-1);
    }
    name = p->parseConfiguration(line);
    pin_id = _mapping[name];
    if (p != NULL && pin_id != -1 && name != "") {
        _pins[pin_id] = p;
    }
}

void
Arduino::addPin(string signal_name, uint8_t pin_id) {
    _mapping[signal_name] = pin_id;
}

void
Arduino::addSerial(string signal_name, HardwareSerial *serial) {
    _mapping[signal_name] = serial->pin();
}

/* Reporting facilities */
void
Arduino::report() {
    map<int, Pin*>::iterator it;

    for (it = _pins.begin(); it != _pins.end(); it++) {
        it->second->report();
    }
}

<commit_msg>Added log flushes to help keep files up to date.<commit_after>#include <iostream>
#include <cmath>
#include <fstream>
#include <sstream>
#include <cassert>
#include <iomanip>
#include "private_config.h"

using namespace std;

void
addTime(ardu_clock_t &t, int ticks) {
    t._ticks += ticks;
    while (t._ticks > TICKS_PER_SECOND) {
        t._seconds += 1;
        t._ticks -= TICKS_PER_SECOND;
    }
}

void
print_clock(string n, ardu_clock_t t){
    ardu->_debug << n << " " << t._seconds << "." << setw(FIELD_WIDTH) << setfill('0') << t._ticks << "\n";

    ardu->_debug.flush();
}

Arduino::Arduino() {
    _log.exceptions ( ifstream::failbit | ifstream::badbit );
    _debug.exceptions ( ifstream::failbit | ifstream::badbit );

    _log.open("dispatch.log", fstream::out | fstream::trunc);
    _debug.open("debug.log",  fstream::out | fstream::trunc);
    cout << "Setting up the Arduino\n";

    _ticks = 0 ;
    _total_ticks = 0;
    _scenario_length._seconds = 0;
    _scenario_length._ticks = 0;
    _registered_identifers = "";
}

Arduino::~Arduino() {
    if (_log.is_open()) {
        _log << "\n\n";
        _log.flush();
        _log.close();
    }
    if (_debug.is_open()) {
        _debug << "\n\n";
        _debug.flush();
        _debug.close();
    }
}

void
Arduino::configurePin(uint8_t pin_id, uint8_t mode) {
    map<int, Pin*>::iterator it;
    it = _pins.find(pin_id);

    if (it != _pins.end()) {
        _pins[pin_id]->_mode = mode;
        _debug << "Configuring Pin " << (int)pin_id << " to mode: " << (int)mode <<  "\n";
    }
    else {
        _debug << "Error, pin configured that is not registed\n";
    }
}

bool
Arduino::addInputFile(char *name) {
    ifstream ifile;
    bool header_parsed = false;

    ifile.open(name, ifstream::in);

    while (ifile.good()) {
        string line;
        getline(ifile, line);
        if (line.compare("---") == 0) {
            header_parsed = true;
            continue;
        }
        size_t found = line.find(" ");

        if (found != string::npos) {
            string word = line.substr(0, found);
            if (header_parsed) {
                _debug << "Scanning signals\n";
                registerSignal(word, line);
            }
            else {
                _debug << "Scanning Header\n";
                scanHeaderChunk(word, line);
            }
        }
    }

    ifile.close();

    _debug << "done parsing file\n";
    return true;
}

void
Arduino::runScenario() {
    _timer._seconds = 0;
    _timer._ticks   = 0;
    setup();
    _debug << "Attempting to run the Scenario\n\n";

    print_clock("Scenario Length: ", _scenario_length);
    print_clock("Runtime Timer:", _timer);
    while (!((_timer._seconds > _scenario_length._seconds) || (_timer._seconds == _scenario_length._seconds && _timer._ticks >= _scenario_length._ticks))) {
        loop();
        addTicks(1);
        updatePinState();
    }
    print_clock("Scenario Length: ", _scenario_length);
    print_clock("Runtime Timer:", _timer);

    cout << "--------------------------\n";
}

void
Arduino::addTicks(uint64_t length) {
    _timer._ticks += length;
    if (_timer._ticks > TICKS_PER_SECOND) {
        _timer._seconds++;
        _timer._ticks -= TICKS_PER_SECOND;
    }
}

void
Arduino::updatePinState() {
    // Report Changes in State
    map<int, Pin*>::iterator it;
    for (it = _pins.begin(); it != _pins.end(); it++) {
        it->second->setState(_timer);
    }
}

/*
 * Analog Reads take 100 ms
 * Digital Reads 58 cycles
 */
int
Arduino::getPin(uint8_t pin_id) {
    if (_pins.find(pin_id) == _pins.end())
        return LOW;
    else {
        if (_pins[pin_id]->_val_type == VT_SERIAL) {
            return LOW;
        }
        else if (_pins[pin_id]->_val_type == VT_DIGITAL) {
            addTicks(58);
            return _pins[pin_id]->_state;
        }
        else if (_pins[pin_id]->_val_type == VT_ANALOG) {
            addTicks(MS2T(100));
            return _pins[pin_id]->_state;
        }
        else
            return LOW;
    }
}

void
Arduino::setPin(uint8_t pin_id, uint8_t val) {
    if (_pins[pin_id]->_state != val) {
        _pins[pin_id]->_state = val;
        _pins[pin_id]->_flags &= 0x1;
        cout << timestamp() << "\nUpdating value for: " << static_cast<int>(pin_id) << " " << static_cast<int>(val) << "\n";
    }
}

void
Arduino::dispatchSignal(const char *signal_id) {
    int ticks = _pins[_mapping[signal_id]]->process();

    _timer._ticks += ticks;
    while (_timer._ticks > TICKS_PER_SECOND) {
        _timer._seconds += 1;
        _timer._ticks -= TICKS_PER_SECOND;
    }

    updatePinState();
    _log << "Dispatching signal " << signal_id << " for " << _mapping[signal_id] << " a " << ticks << "\n";
}

string
Arduino::timestamp() {
    ostringstream result(ostringstream::out);
    result << static_cast<int>(_timer._seconds) << "s " << static_cast<int>(_timer._ticks) << "t";
    return result.str();
}

void
Arduino::scanHeaderChunk(string identifier, string line) {
    if (identifier == "length:") {
        double run_time;
        istringstream is;

        is.str(line.substr(identifier.length(), line.length() - identifier.length()));
        is >> run_time;

        cout << "Configuration parsed runtime of " << run_time << "\n";
        _scenario_length._seconds = (int)run_time;
        _scenario_length._ticks = (run_time - floor(run_time)) * TICKS_PER_SECOND;
    }
    else if (identifier == "identifiers:") {
        _registered_identifers = line.substr(identifier.length(), line.length() - identifier.length());
    }
    else if (identifier == "#") {
        // this is a comment, do nothing with this line
    }
    else {
        cout << "Unrecognized header configuration name \"" << identifier << "\"\n";
    }
}

void
Arduino::registerSignal(string identifer, string line) {
    Pin *p = NULL;
    int pin_id = -1;
    string name = "";
    if (identifer == "det") {
        p = new DetPin();
    }
    else if (identifer == "uni") {
        p = new UniPin();
    }
    else if (identifer == "exp") {
        p = new ExpPin();
    }
    else {
        cout << "Bad configuration line \"" << line << "\"\n";
        exit(-1);
    }
    name = p->parseConfiguration(line);
    pin_id = _mapping[name];
    if (p != NULL && pin_id != -1 && name != "") {
        _pins[pin_id] = p;
    }
}

void
Arduino::addPin(string signal_name, uint8_t pin_id) {
    _mapping[signal_name] = pin_id;
}

void
Arduino::addSerial(string signal_name, HardwareSerial *serial) {
    _mapping[signal_name] = serial->pin();
}

/* Reporting facilities */
void
Arduino::report() {
    map<int, Pin*>::iterator it;

    for (it = _pins.begin(); it != _pins.end(); it++) {
        it->second->report();
    }
}

<|endoftext|>


<commit_before>/* Copyright (c) 2010 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/**
 * \file
 * Implementation for debug logs.
 */

#include <stdarg.h>
#include <sys/time.h>
#include "Logging.h"

namespace RAMCloud {

namespace TestLog {
    /**
     * The current predicate which is used to select test log entries.
     * This symbol is not exported.
     */
    bool (*predicate)(string) = 0;

    /**
     * Whether test log entries should be recorded.
     * This symbol is not exported.
     */
    bool enabled = false;

    /**
     * The current test log.
     * This symbol is not exported.
     */
    string message;

    /// Clear the contents of the test log.
    void
    clear()
    {
        message = "";
    }

    /**
     * Clear the test log and quit recording test log entries and
     * remove any predicate that was installed.
     */
    void
    disable()
    {
        clear();
        enabled = false;
        predicate = NULL;
    }

    /// Clear the test log and begin recording test log entries.
    void
    enable()
    {
        clear();
        enabled = true;
    }

    /**
     * Returns the current test log.
     *
     * \return
     *      The current test log.
     */
    string
    get()
    {
        return message;
    }

    /**
     * Don't call this directly, see TEST_LOG instead.
     *
     * Log a message to the test log for unit testing.
     *
     * \param[in] func
     *      The result of __PRETTY_FUNCTION__.
     * \param[in] format
     *      See #LOG except the string should end with a newline character.
     * \param[in] ...
     *      See #LOG.
     */
    void
    log(const char* func,
        const char* format, ...)
    {
        va_list ap;
        char line[512];

        if (predicate && !predicate(func))
            return;

        if (message.length())
            message += " | ";

        snprintf(line, sizeof(line), "%s: ", func);
        message += line;

        va_start(ap, format);
        vsnprintf(line, sizeof(line), format, ap);
        va_end(ap);
        message += line;
    }

    /**
     * Install a predicate to select only the relevant test log entries.
     *
     * \param[in] pred
     *      A predicate which is passed the value of __PRETTY_FUNCTION__
     *      from the TEST_LOG call site.  The predicate should return true
     *      precisely when the test log entry for the corresponding TEST_LOG
     *      invocation should be included in the test log.
     */
    void
    setPredicate(bool (*pred)(string))
    {
        predicate = pred;
    }
} // end RAMCloud::TestLog

Logger logger(NOTICE);

/**
 * Friendly names for each #LogLevel value.
 * Keep this in sync with the LogLevel enum.
 */
static const char* logLevelNames[] = {"(none)", "ERROR", "WARNING",
                                      "NOTICE", "DEBUG"};

/**
 * Friendly names for each #LogModule value.
 * Keep this in sync with the LogModule enum.
 */
static const char* logModuleNames[] = {"default"};

/**
 * Create a new debug logger.
 * \param[in] level
 *      Messages for all modules at least as important as \a level will be
 *      logged.
 */
Logger::Logger(LogLevel level) : stream(stderr)
{
    setLogLevels(level);
}

/**
 * Set the log level for a particular module.
 * \param[in] module
 *      The module whose level to set.
 * \param[in] level
 *      Messages for \a module at least as important as \a level will be
 *      logged.
 */
void
Logger::setLogLevel(LogModule module, LogLevel level)
{
    logLevels[module] = level;
}

/**
 * Set the log level for a particular module.
 * \param[in] module
 *      The module whose level to set.
 * \param[in] level
 *      Messages for \a module at least as important as \a level will be
 *      logged. This will be clamped to a valid LogLevel if it is out of range.
 */
void
Logger::setLogLevel(LogModule module, int level)
{
    if (level < 0)
        level = 0;
    else if (level >= NUM_LOG_LEVELS)
        level = NUM_LOG_LEVELS - 1;
    setLogLevel(module, static_cast<LogLevel>(level));
}

/**
 * Change the log level by a relative amount for a particular module.
 * \param[in] module
 *      The module whose level to change.
 * \param[in] delta
 *      The amount (positive or negative) by which to change the log level
 *      of \a module. The resulting level will be clamped to a valid LogLevel
 *      if it is out of range.
 */
void
Logger::changeLogLevel(LogModule module, int delta)
{
    int level = static_cast<int>(logLevels[module]);
    setLogLevel(module, level + delta);
}

/**
 * Set the log level for all modules.
 * \param[in] level
 *      Messages for the modules at least as important as \a level will be
 *      logged.
 */
void
Logger::setLogLevels(LogLevel level)
{
    for (int i = 0; i < NUM_LOG_MODULES; i++) {
        LogModule module = static_cast<LogModule>(i);
        setLogLevel(module, level);
    }
}
/**
 * Set the log level for all modules.
 * \param[in] level
 *      Messages for all modules at least as important as \a level will be
 *      logged. This will be clamped to a valid LogLevel if it is out of range.
 */
void
Logger::setLogLevels(int level)
{
    if (level < 0)
        level = 0;
    else if (level >= NUM_LOG_LEVELS)
        level = NUM_LOG_LEVELS - 1;
    setLogLevels(static_cast<LogLevel>(level));
}

/**
 * Change the log level by a relative amount for all modules.
 * \param[in] delta
 *      The amount (positive or negative) by which to change the log level
 *      of the modules. The resulting level will be clamped to a valid LogLevel
 *      if it is out of range.
 */
void
Logger::changeLogLevels(int delta)
{
    for (int i = 0; i < NUM_LOG_MODULES; i++) {
        LogModule module = static_cast<LogModule>(i);
        changeLogLevel(module, delta);
    }
}

/**
 * Return the number of characters of __FILE__ that make up the path prefix.
 * That is, __FILE__ plus this value will be the relative path from the top
 * directory of the RAMCloud repo.
 */
static int
length__FILE__Prefix()
{
    const char* start = __FILE__;
    const char* match = strstr(__FILE__, "src/Logging.cc");
    assert(match != NULL);
    return (match - start);
}

/**
 * Log a message for the system administrator.
 * \param[in] module
 *      The module to which the message pertains.
 * \param[in] level
 *      See #LOG.
 * \param[in] file
 *      The result of __FILE__.
 * \param[in] line
 *      The result of __LINE__.
 * \param[in] format
 *      See #LOG except the string should end with a newline character.
 * \param[in] ...
 *      See #LOG.
 */
void
Logger::logMessage(LogModule module, LogLevel level,
                   const char* file, uint32_t line,
                   const char* format, ...)
{
    static int fileCharsToSkip = length__FILE__Prefix();

    va_list ap;
    struct timeval now;

    gettimeofday(&now, NULL);
    fprintf(stream, "%010u.%06u %s:%d %s %s: ",
            now.tv_sec, now.tv_usec,
            file + fileCharsToSkip, line,
            logModuleNames[module],
            logLevelNames[level]);

    va_start(ap, format);
    vfprintf(stream, format, ap);
    va_end(ap);

    fflush(stream);
}

/**
 * Format a message for use in #DIE().
 * \param[in] module
 *      See #logMessage().
 * \param[in] level
 *      See #logMessage().
 * \param[in] file
 *      See #logMessage().
 * \param[in] line
 *      See #logMessage().
 * \param[in] format
 *      See #logMessage().
 * \param[in] ...
 *      See #logMessage().
 * \return
 *      A string containing the formatted message.
 */
std::string
Logger::getMessage(LogModule module, LogLevel level,
                   const char* file, uint32_t line,
                   const char* format, ...)
{
    static int fileCharsToSkip = length__FILE__Prefix();
    std::string message;
    char buf[1024];
    va_list ap;

    snprintf(buf, sizeof(buf), "%s:%d %s %s: ",
             file + fileCharsToSkip, line,
             logModuleNames[module],
             logLevelNames[level]);
    message.append(buf);

    va_start(ap, format);
    vsnprintf(buf, sizeof(buf), format, ap);
    va_end(ap);
    message.append(buf);

    return message;
}

} // end RAMCloud

<commit_msg>fasttransport: Fixed bug causing TEST_LOG messages to build up.<commit_after>/* Copyright (c) 2010 Stanford University
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/**
 * \file
 * Implementation for debug logs.
 */

#include <stdarg.h>
#include <sys/time.h>
#include "Logging.h"

namespace RAMCloud {

namespace TestLog {
    /**
     * The current predicate which is used to select test log entries.
     * This symbol is not exported.
     */
    bool (*predicate)(string) = 0;

    /**
     * Whether test log entries should be recorded.
     * This symbol is not exported.
     */
    bool enabled = false;

    /**
     * The current test log.
     * This symbol is not exported.
     */
    string message;

    /// Clear the contents of the test log.
    void
    clear()
    {
        message = "";
    }

    /**
     * Clear the test log and quit recording test log entries and
     * remove any predicate that was installed.
     */
    void
    disable()
    {
        clear();
        enabled = false;
        predicate = NULL;
    }

    /// Clear the test log and begin recording test log entries.
    void
    enable()
    {
        clear();
        enabled = true;
    }

    /**
     * Returns the current test log.
     *
     * \return
     *      The current test log.
     */
    string
    get()
    {
        return message;
    }

    /**
     * Don't call this directly, see TEST_LOG instead.
     *
     * Log a message to the test log for unit testing.
     *
     * \param[in] func
     *      The result of __PRETTY_FUNCTION__.
     * \param[in] format
     *      See #LOG except the string should end with a newline character.
     * \param[in] ...
     *      See #LOG.
     */
    void
    log(const char* func,
        const char* format, ...)
    {
        va_list ap;
        char line[512];

        if (!enabled || (predicate && !predicate(func)))
            return;

        if (message.length())
            message += " | ";

        snprintf(line, sizeof(line), "%s: ", func);
        message += line;

        va_start(ap, format);
        vsnprintf(line, sizeof(line), format, ap);
        va_end(ap);
        message += line;
    }

    /**
     * Install a predicate to select only the relevant test log entries.
     *
     * \param[in] pred
     *      A predicate which is passed the value of __PRETTY_FUNCTION__
     *      from the TEST_LOG call site.  The predicate should return true
     *      precisely when the test log entry for the corresponding TEST_LOG
     *      invocation should be included in the test log.
     */
    void
    setPredicate(bool (*pred)(string))
    {
        predicate = pred;
    }
} // end RAMCloud::TestLog

Logger logger(NOTICE);

/**
 * Friendly names for each #LogLevel value.
 * Keep this in sync with the LogLevel enum.
 */
static const char* logLevelNames[] = {"(none)", "ERROR", "WARNING",
                                      "NOTICE", "DEBUG"};

/**
 * Friendly names for each #LogModule value.
 * Keep this in sync with the LogModule enum.
 */
static const char* logModuleNames[] = {"default"};

/**
 * Create a new debug logger.
 * \param[in] level
 *      Messages for all modules at least as important as \a level will be
 *      logged.
 */
Logger::Logger(LogLevel level) : stream(stderr)
{
    setLogLevels(level);
}

/**
 * Set the log level for a particular module.
 * \param[in] module
 *      The module whose level to set.
 * \param[in] level
 *      Messages for \a module at least as important as \a level will be
 *      logged.
 */
void
Logger::setLogLevel(LogModule module, LogLevel level)
{
    logLevels[module] = level;
}

/**
 * Set the log level for a particular module.
 * \param[in] module
 *      The module whose level to set.
 * \param[in] level
 *      Messages for \a module at least as important as \a level will be
 *      logged. This will be clamped to a valid LogLevel if it is out of range.
 */
void
Logger::setLogLevel(LogModule module, int level)
{
    if (level < 0)
        level = 0;
    else if (level >= NUM_LOG_LEVELS)
        level = NUM_LOG_LEVELS - 1;
    setLogLevel(module, static_cast<LogLevel>(level));
}

/**
 * Change the log level by a relative amount for a particular module.
 * \param[in] module
 *      The module whose level to change.
 * \param[in] delta
 *      The amount (positive or negative) by which to change the log level
 *      of \a module. The resulting level will be clamped to a valid LogLevel
 *      if it is out of range.
 */
void
Logger::changeLogLevel(LogModule module, int delta)
{
    int level = static_cast<int>(logLevels[module]);
    setLogLevel(module, level + delta);
}

/**
 * Set the log level for all modules.
 * \param[in] level
 *      Messages for the modules at least as important as \a level will be
 *      logged.
 */
void
Logger::setLogLevels(LogLevel level)
{
    for (int i = 0; i < NUM_LOG_MODULES; i++) {
        LogModule module = static_cast<LogModule>(i);
        setLogLevel(module, level);
    }
}
/**
 * Set the log level for all modules.
 * \param[in] level
 *      Messages for all modules at least as important as \a level will be
 *      logged. This will be clamped to a valid LogLevel if it is out of range.
 */
void
Logger::setLogLevels(int level)
{
    if (level < 0)
        level = 0;
    else if (level >= NUM_LOG_LEVELS)
        level = NUM_LOG_LEVELS - 1;
    setLogLevels(static_cast<LogLevel>(level));
}

/**
 * Change the log level by a relative amount for all modules.
 * \param[in] delta
 *      The amount (positive or negative) by which to change the log level
 *      of the modules. The resulting level will be clamped to a valid LogLevel
 *      if it is out of range.
 */
void
Logger::changeLogLevels(int delta)
{
    for (int i = 0; i < NUM_LOG_MODULES; i++) {
        LogModule module = static_cast<LogModule>(i);
        changeLogLevel(module, delta);
    }
}

/**
 * Return the number of characters of __FILE__ that make up the path prefix.
 * That is, __FILE__ plus this value will be the relative path from the top
 * directory of the RAMCloud repo.
 */
static int
length__FILE__Prefix()
{
    const char* start = __FILE__;
    const char* match = strstr(__FILE__, "src/Logging.cc");
    assert(match != NULL);
    return (match - start);
}

/**
 * Log a message for the system administrator.
 * \param[in] module
 *      The module to which the message pertains.
 * \param[in] level
 *      See #LOG.
 * \param[in] file
 *      The result of __FILE__.
 * \param[in] line
 *      The result of __LINE__.
 * \param[in] format
 *      See #LOG except the string should end with a newline character.
 * \param[in] ...
 *      See #LOG.
 */
void
Logger::logMessage(LogModule module, LogLevel level,
                   const char* file, uint32_t line,
                   const char* format, ...)
{
    static int fileCharsToSkip = length__FILE__Prefix();

    va_list ap;
    struct timeval now;

    gettimeofday(&now, NULL);
    fprintf(stream, "%010u.%06u %s:%d %s %s: ",
            now.tv_sec, now.tv_usec,
            file + fileCharsToSkip, line,
            logModuleNames[module],
            logLevelNames[level]);

    va_start(ap, format);
    vfprintf(stream, format, ap);
    va_end(ap);

    fflush(stream);
}

/**
 * Format a message for use in #DIE().
 * \param[in] module
 *      See #logMessage().
 * \param[in] level
 *      See #logMessage().
 * \param[in] file
 *      See #logMessage().
 * \param[in] line
 *      See #logMessage().
 * \param[in] format
 *      See #logMessage().
 * \param[in] ...
 *      See #logMessage().
 * \return
 *      A string containing the formatted message.
 */
std::string
Logger::getMessage(LogModule module, LogLevel level,
                   const char* file, uint32_t line,
                   const char* format, ...)
{
    static int fileCharsToSkip = length__FILE__Prefix();
    std::string message;
    char buf[1024];
    va_list ap;

    snprintf(buf, sizeof(buf), "%s:%d %s %s: ",
             file + fileCharsToSkip, line,
             logModuleNames[module],
             logLevelNames[level]);
    message.append(buf);

    va_start(ap, format);
    vsnprintf(buf, sizeof(buf), format, ap);
    va_end(ap);
    message.append(buf);

    return message;
}

} // end RAMCloud

<|endoftext|>


<commit_before>/*
Copyright 2017 VMware, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "complexComparison.h"

namespace P4 {

const IR::Expression* RemoveComplexComparisons::explode(
    Util::SourceInfo srcInfo,
    const IR::Type* leftType, const IR::Expression* left,
    const IR::Type* rightType, const IR::Expression* right) {

    // we allow several cases
    // header == header
    // header == list (tuple)
    // list == header
    // list == list
    // struct == struct
    // array == array
    // struct == list
    // list == struct

    auto rightTuple = rightType->to<IR::Type_Tuple>();
    auto leftTuple = leftType->to<IR::Type_Tuple>();
    if (leftTuple && !rightTuple)
        // put the tuple on the right if it is the only one,
        // so we handle fewer cases
        return explode(srcInfo, rightType, right, leftType, left);

    if (auto ht = leftType->to<IR::Type_Header>()) {
        auto lmethod = new IR::Member(left, IR::Type_Header::isValid);
        auto lvalid = new IR::MethodCallExpression(srcInfo, lmethod);
        auto linvalid = new IR::LNot(srcInfo, lvalid);

        const IR::Expression* rvalid;
        if (!rightTuple) {
            auto rmethod = new IR::Member(right, IR::Type_Header::isValid);
            rvalid = new IR::MethodCallExpression(srcInfo, rmethod);
        } else {
            rvalid = new IR::BoolLiteral(true);
        }

        auto rinvalid = new IR::LNot(srcInfo, rvalid);
        auto invalid = new IR::LAnd(srcInfo, linvalid, rinvalid);
        auto valid = new IR::LAnd(srcInfo, lvalid, rvalid);
        size_t index = 0;
        for (auto f : ht->fields) {
            auto ftype = f->type;
            auto fleft = new IR::Member(srcInfo, left, f->name);
            const IR::Expression* fright;
            const IR::Type* rightType;
            if (!rightTuple) {
                fright = new IR::Member(srcInfo, right, f->name);
                rightType = f->type;
            } else {
                fright = right->to<IR::ListExpression>()->components.at(index);
                rightType = rightTuple->components.at(index);
            }
            auto rec = explode(srcInfo, ftype, fleft, rightType, fright);
            valid = new IR::LAnd(srcInfo, valid, rec);
            index++;
        }
        auto result = new IR::LOr(srcInfo, invalid, valid);
        return result;
    } else if (auto st = leftType->to<IR::Type_StructLike>()) {
        // Works for structs and unions
        const IR::Expression* result = new IR::BoolLiteral(true);
        size_t index = 0;
        for (auto f : st->fields) {
            auto ftype = f->type;
            auto fleft = new IR::Member(srcInfo, left, f->name);
            const IR::Expression* fright;
            const IR::Type* rightType;
            if (!rightTuple) {
                fright = new IR::Member(srcInfo, right, f->name);
            } else {
                fright = right->to<IR::ListExpression>()->components.at(index);
                rightType = rightTuple->components.at(index);
            }
            index++;
            auto rec = explode(srcInfo, ftype, fleft, rightType, fright);
            result = new IR::LAnd(srcInfo, result, rec);
        }
        return result;
    } else if (auto at = leftType->to<IR::Type_Stack>()) {
        auto size = at->getSize();
        const IR::Expression* result = new IR::BoolLiteral(true);
        BUG_CHECK(rightType->is<IR::Type_Stack>(),
                  "%1%: comparing stack with %1%", left, rightType);
        for (unsigned i=0; i < size; i++) {
            auto index = new IR::Constant(i);
            auto lelem = new IR::ArrayIndex(srcInfo, left, index);
            auto relem = new IR::ArrayIndex(srcInfo, right, index);
            auto rec = explode(srcInfo, at->elementType, lelem, at->elementType, relem);
            result = new IR::LAnd(srcInfo, result, rec);
        }
        return result;
    } else if (leftTuple) {
        BUG_CHECK(rightTuple, "%1% vs %2%: unexpected comparison", left, right);
        const IR::Expression* result = new IR::BoolLiteral(true);
        auto leftList = left->to<IR::ListExpression>();
        for (size_t index = 0; index < leftList->components.size(); index++) {
            auto fleft = leftList->components.at(index);
            auto leftType = leftTuple->components.at(index);
            auto fright = right->to<IR::ListExpression>()->components.at(index);
            auto rightType = rightTuple->components.at(index);
            auto rec = explode(srcInfo, leftType, fleft, rightType, fright);
            result = new IR::LAnd(srcInfo, result, rec);
        }
        return result;
    } else {
        return new IR::Equ(srcInfo, left, right);
    }
}

const IR::Node* RemoveComplexComparisons::postorder(IR::Operation_Binary* expression) {
    if (!expression->is<IR::Neq>() && !expression->is<IR::Equ>())
        return expression;
    auto ltype = typeMap->getType(expression->left, true);
    auto rtype = typeMap->getType(expression->right, true);
    if (!ltype->is<IR::Type_StructLike>() && !ltype->is<IR::Type_Stack>() &&
        !ltype->is<IR::Type_Tuple>())
        return expression;
    auto result = explode(expression->srcInfo, ltype, expression->left, rtype, expression->right);
    if (expression->is<IR::Neq>())
        result = new IR::LNot(expression->srcInfo, result);
    return result;
}

}  // namespace P4
<commit_msg>Fix uninitialized variable bug in ComplexComparison<commit_after>/*
Copyright 2017 VMware, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "complexComparison.h"

namespace P4 {

const IR::Expression* RemoveComplexComparisons::explode(
    Util::SourceInfo srcInfo,
    const IR::Type* leftType, const IR::Expression* left,
    const IR::Type* rightType, const IR::Expression* right) {

    // we allow several cases
    // header == header
    // header == list (tuple)
    // list == header
    // list == list
    // struct == struct
    // array == array
    // struct == list
    // list == struct

    auto rightTuple = rightType->to<IR::Type_Tuple>();
    auto leftTuple = leftType->to<IR::Type_Tuple>();
    if (leftTuple && !rightTuple)
        // put the tuple on the right if it is the only one,
        // so we handle fewer cases
        return explode(srcInfo, rightType, right, leftType, left);

    if (auto ht = leftType->to<IR::Type_Header>()) {
        auto lmethod = new IR::Member(left, IR::Type_Header::isValid);
        auto lvalid = new IR::MethodCallExpression(srcInfo, lmethod);
        auto linvalid = new IR::LNot(srcInfo, lvalid);

        const IR::Expression* rvalid;
        if (!rightTuple) {
            auto rmethod = new IR::Member(right, IR::Type_Header::isValid);
            rvalid = new IR::MethodCallExpression(srcInfo, rmethod);
        } else {
            rvalid = new IR::BoolLiteral(true);
        }

        auto rinvalid = new IR::LNot(srcInfo, rvalid);
        auto invalid = new IR::LAnd(srcInfo, linvalid, rinvalid);
        auto valid = new IR::LAnd(srcInfo, lvalid, rvalid);
        size_t index = 0;
        for (auto f : ht->fields) {
            auto ftype = f->type;
            auto fleft = new IR::Member(srcInfo, left, f->name);
            const IR::Expression* fright;
            const IR::Type* rightType;
            if (!rightTuple) {
                fright = new IR::Member(srcInfo, right, f->name);
                rightType = f->type;
            } else {
                fright = right->to<IR::ListExpression>()->components.at(index);
                rightType = rightTuple->components.at(index);
            }
            auto rec = explode(srcInfo, ftype, fleft, rightType, fright);
            valid = new IR::LAnd(srcInfo, valid, rec);
            index++;
        }
        auto result = new IR::LOr(srcInfo, invalid, valid);
        return result;
    } else if (auto st = leftType->to<IR::Type_StructLike>()) {
        // Works for structs and unions
        const IR::Expression* result = new IR::BoolLiteral(true);
        size_t index = 0;
        for (auto f : st->fields) {
            auto ftype = f->type;
            auto fleft = new IR::Member(srcInfo, left, f->name);
            const IR::Expression* fright;
            const IR::Type* rightType;
            if (!rightTuple) {
                fright = new IR::Member(srcInfo, right, f->name);
                rightType = f->type;
            } else {
                fright = right->to<IR::ListExpression>()->components.at(index);
                rightType = rightTuple->components.at(index);
            }
            index++;
            auto rec = explode(srcInfo, ftype, fleft, rightType, fright);
            result = new IR::LAnd(srcInfo, result, rec);
        }
        return result;
    } else if (auto at = leftType->to<IR::Type_Stack>()) {
        auto size = at->getSize();
        const IR::Expression* result = new IR::BoolLiteral(true);
        BUG_CHECK(rightType->is<IR::Type_Stack>(),
                  "%1%: comparing stack with %1%", left, rightType);
        for (unsigned i=0; i < size; i++) {
            auto index = new IR::Constant(i);
            auto lelem = new IR::ArrayIndex(srcInfo, left, index);
            auto relem = new IR::ArrayIndex(srcInfo, right, index);
            auto rec = explode(srcInfo, at->elementType, lelem, at->elementType, relem);
            result = new IR::LAnd(srcInfo, result, rec);
        }
        return result;
    } else if (leftTuple) {
        BUG_CHECK(rightTuple, "%1% vs %2%: unexpected comparison", left, right);
        const IR::Expression* result = new IR::BoolLiteral(true);
        auto leftList = left->to<IR::ListExpression>();
        for (size_t index = 0; index < leftList->components.size(); index++) {
            auto fleft = leftList->components.at(index);
            auto leftType = leftTuple->components.at(index);
            auto fright = right->to<IR::ListExpression>()->components.at(index);
            auto rightType = rightTuple->components.at(index);
            auto rec = explode(srcInfo, leftType, fleft, rightType, fright);
            result = new IR::LAnd(srcInfo, result, rec);
        }
        return result;
    } else {
        return new IR::Equ(srcInfo, left, right);
    }
}

const IR::Node* RemoveComplexComparisons::postorder(IR::Operation_Binary* expression) {
    if (!expression->is<IR::Neq>() && !expression->is<IR::Equ>())
        return expression;
    auto ltype = typeMap->getType(expression->left, true);
    auto rtype = typeMap->getType(expression->right, true);
    if (!ltype->is<IR::Type_StructLike>() && !ltype->is<IR::Type_Stack>() &&
        !ltype->is<IR::Type_Tuple>())
        return expression;
    auto result = explode(expression->srcInfo, ltype, expression->left, rtype, expression->right);
    if (expression->is<IR::Neq>())
        result = new IR::LNot(expression->srcInfo, result);
    return result;
}

}  // namespace P4
<|endoftext|>


<commit_before>/**
 * @file	src/Module.cpp
 * @date	dec. 2015
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2015 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#include "Module.h"
#include "ModuleFactory.h"
#include "ModuleManager.h"
#include "ThreadManager.h"
#include "ModuleTask.h"

#include "OutPort.h"

#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"

std::vector<std::string> Module::names;
Poco::RWLock Module::namesLock;

void Module::notifyCreation()
{
    // if not EmptyModule, add this to module manager
    if (mParent)
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().addModule(this);
}

Module::~Module()
{
	// TODO: tasks?

    // notify parent factory
    if (mParent)
    {
        mParent->removeChildModule(this);

        // notify module manager
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().removeModule(this);
    }
}

#include "Poco/Exception.h"

void Module::setInternalName(std::string internalName)
{
    namesLock.writeLock();

    switch (checkName(internalName))
    {
    case nameOk:
        mInternalName = internalName;
        names.push_back(mInternalName);
        namesLock.unlock();
        return;
    case nameExists:
        namesLock.unlock();
        throw Poco::ExistsException("setInternalName",
                internalName + " already in use");
    case nameBadSyntax:
        namesLock.unlock();
        throw Poco::SyntaxException("setInternalName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

void Module::setCustomName(std::string customName)
{
    if (customName.empty() || customName.compare(internalName())==0)
    {
        mName = internalName();

        // update conf file prefix key
        setPrefixKey("module." + mName);

        return;
    }

    namesLock.writeLock();

    switch (checkName(customName))
    {
    case nameOk:
        mName = customName;
        names.push_back(mName);
        namesLock.unlock();
        return;
    case nameExists:
        freeInternalName();
        namesLock.unlock();
        throw Poco::ExistsException("setCustomName",
                customName + " already in use");
    case nameBadSyntax:
        freeInternalName();
        namesLock.unlock();
        throw Poco::SyntaxException("setCustomName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

ModuleFactory* Module::parent()
{
    if (mParent)
        return mParent;
    else
        throw Poco::InvalidAccessException("parent",
                "This module has no valid parent factory");
}

#include "Poco/RegularExpression.h"

Module::NameStatus Module::checkName(std::string newName)
{
    // check syntax
    Poco::RegularExpression regex("^[0-9a-zA-Z\\._-]+$");
    if (!regex.match(newName))
        return nameBadSyntax;

    // check existance
    for (std::vector<std::string>::iterator it = names.begin(),
            ite = names.end(); it != ite; it++)
        if (it->compare(newName)==0)
            return nameExists;

    return nameOk;
}

void Module::freeInternalName()
{
    // verify that this is a module creation process
    if (!name().empty())
        return;

    for (std::vector<std::string>::reverse_iterator it = names.rbegin(),
            ite = names.rend(); it != ite; it++ )
    {
        if (it->compare(internalName())==0)
        {
            names.erase((it+1).base());
            return;
        }
    }
}

void Module::run(ModuleTask* pTask)
{
	setRunningTask(pTask);

	taskMngtMutex.lock();
	if (startSyncPending)
	{
		startSyncPending = false;
		taskMngtMutex.unlock();
	}
	taskMngtMutex.unlock();

	try
	{
		if (cancelling)
			throw Poco::RuntimeException(name() +
					": can not run a new task, "
					"the module is cancelling");

		expireOutData();

		setRunningState(ModuleTask::retrievingInDataLocks);

		resetDone = false;
		cancelDone = false;

		int startCond = startCondition();

		mergeTasks(portsWithNewData());

		setRunningState(ModuleTask::processing);
		process(startCond);
	}
	catch (...)
	{
		releaseAllInPorts();
		releaseAllOutPorts();
		throw;
	}

	releaseAllInPorts();
	releaseAllOutPorts();
}

bool Module::sleep(long milliseconds)
{
	if (*runningTask)
		return (*runningTask)->sleep(milliseconds);

	Poco::Thread::sleep(milliseconds);
	return false;
}

bool Module::yield()
{
	if (*runningTask)
		return (*runningTask)->yield();

	Poco::Thread::yield();
	return false;
}

void Module::setProgress(float progress)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setProgress(progress);
}

bool Module::isCancelled()
{
	if (*runningTask == NULL)
		return false;

	return (*runningTask)->isCancelled();
}

InPort* Module::triggingPort()
{
	if (*runningTask)
		return (*runningTask)->triggingPort();

	throw Poco::RuntimeException(name(), "querying trigging port. not in a task");
}

void Module::setRunningState(ModuleTask::RunningStates state)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setRunningState(state);
}

ModuleTask::RunningStates Module::getRunningState()
{
	if (*runningTask == NULL)
		return ModuleTask::processing;

	return (*runningTask)->getRunningState();
}

void Module::enqueueTask(ModuleTask* task)
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex);

	// take ownership of the task.
	Poco::Util::Application::instance()
				             .getSubsystem<ThreadManager>()
				             .registerNewModuleTask(task);

	allTasks.insert(task);
	taskQueue.push_back(task);

	if (taskQueue.size()>1)
	{
		poco_information(logger(), task->name()
					+ ": tasks are already enqueued for " + name());
		return;
	}

	if (!taskIsRunning())
		popTask();
//	else
//		poco_information(logger(), name() + ": a task is already running");
}

void Module::condCancel()
{
	if (cancelling || cancelDone)
		return;

	cancelling = true;
	// cancel all module tasks
	taskMngtMutex.lock();
	for (std::set<ModuleTask*>::iterator it = allTasks.begin(),
			ite = allTasks.end(); it != ite; it++)
		(*it)->cancel();
	taskMngtMutex.unlock();

	cancel();

	cancelDone = true;
	cancelling = false;
}

void Module::resetWithTargets()
{
	if (reseting || resetDone)
		return;

	reseting = true;

	if (seqRunning())
		condCancel();

	// reset this module
	reset();

	// reset the sequence targets
	resetTargets();

	resetDone = true;
	reseting = false;
}

bool Module::taskIsRunning()
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex); // Ok: recursive mutex

	for (std::set<ModuleTask*>::iterator it = allTasks.begin(),
			ite = allTasks.end(); it != ite; it++)
	{
		switch ((*it)->getState())
		{
		case MergeableTask::TASK_STARTING:
		case MergeableTask::TASK_RUNNING:
			//poco_information(logger(), task->name()
			//		+ ": " + (*it)->name()
			//		+ " is already running for " + name());
			return true;
		case MergeableTask::TASK_FALSE_START:
		case MergeableTask::TASK_IDLE: // probably self
		case MergeableTask::TASK_CANCELLING:
		case MergeableTask::TASK_FINISHED:
			break;
		default:
			poco_bugcheck_msg("unknown task state");
		}
	}

	return false;
}

void Module::popTask()
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex);

	if (taskQueue.empty())
		return;

	ModuleTask* nextTask = taskQueue.front();
	poco_information(logger(), "poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	Poco::Util::Application::instance()
						 .getSubsystem<ThreadManager>()
						 .startModuleTask(nextTask);
}

void Module::popTaskSync()
{
	taskMngtMutex.lock();

	if (taskQueue.empty())
	{
		poco_information(logger(),
			(*runningTask)->name() + ": empty task queue, nothing to sync pop");
		taskMngtMutex.unlock();
		return;
	}

	if (taskIsRunning())
	{
		poco_information(logger(),"sync pop: a task is already running. ");
		taskMngtMutex.unlock();
		return;
	}

	Poco::AutoPtr<ModuleTask> nextTask(taskQueue.front(), true);
	poco_information(logger(), "SYNC poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	startSyncPending = true;

	try
	{
		Poco::Util::Application::instance()
			             .getSubsystem<ThreadManager>()
			             .startSyncModuleTask(nextTask);
	}
	catch (...)
	{
		poco_error(logger(), "can not sync start " + nextTask->name());
		startSyncPending = false;
		taskMngtMutex.unlock();
		throw;
	}
}

void Module::unregisterTask(ModuleTask* task)
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex);
	allTasks.erase(task);
}

void Module::mergeTasks(std::set<size_t> inPortIndexes)
{
	// Poco::FastMutex::ScopedLock lock(taskMngtMutex);
	taskMngtMutex.lock();

	for (std::set<size_t>::iterator it = inPortIndexes.begin(),
			ite = inPortIndexes.end(); it != ite; )
	{
		bool found = false;
		InPort* trigPort;

		try
		{
			trigPort = getInPort(*it);

			if (triggingPort() == trigPort)
			{
				it++;
				continue; // current task
			}

			// seek
			for (std::list<ModuleTask*>::iterator qIt = taskQueue.begin(),
					qIte = taskQueue.end(); qIt != qIte; qIt++)
			{
				poco_information(logger(), "taskQueue includes: " + (*qIt)->name());
				if ((*qIt)->triggingPort() == trigPort)
				{
					found = true;
					(*runningTask)->merge(*qIt);
					taskQueue.erase(qIt);
					poco_information(logger(), "slave task found, merging OK");
					break;
				}
			}
		}
		catch (...)
		{
			taskMngtMutex.unlock();
			throw;
		}

		if (!found)
		{
			taskMngtMutex.unlock();
			poco_warning(logger(),
					"Unable to merge the task for " + trigPort->name()
					+ ". Retry.");
//			if (sleep(500))
			if (yield())
				throw Poco::RuntimeException(name(), "Cancelation upon user request");
			taskMngtMutex.lock();
		}
		else
			it++;
	}

	poco_information(logger(),
		"remaining tasks: " + Poco::NumberFormatter::format(taskQueue.size()));

	taskMngtMutex.unlock();
}
<commit_msg>Add debug info<commit_after>/**
 * @file	src/Module.cpp
 * @date	dec. 2015
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2015 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#include "Module.h"
#include "ModuleFactory.h"
#include "ModuleManager.h"
#include "ThreadManager.h"
#include "ModuleTask.h"

#include "OutPort.h"

#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"

std::vector<std::string> Module::names;
Poco::RWLock Module::namesLock;

void Module::notifyCreation()
{
    // if not EmptyModule, add this to module manager
    if (mParent)
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().addModule(this);
}

Module::~Module()
{
	// TODO: tasks?

    // notify parent factory
    if (mParent)
    {
        mParent->removeChildModule(this);

        // notify module manager
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().removeModule(this);
    }
}

#include "Poco/Exception.h"

void Module::setInternalName(std::string internalName)
{
    namesLock.writeLock();

    switch (checkName(internalName))
    {
    case nameOk:
        mInternalName = internalName;
        names.push_back(mInternalName);
        namesLock.unlock();
        return;
    case nameExists:
        namesLock.unlock();
        throw Poco::ExistsException("setInternalName",
                internalName + " already in use");
    case nameBadSyntax:
        namesLock.unlock();
        throw Poco::SyntaxException("setInternalName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

void Module::setCustomName(std::string customName)
{
    if (customName.empty() || customName.compare(internalName())==0)
    {
        mName = internalName();

        // update conf file prefix key
        setPrefixKey("module." + mName);

        return;
    }

    namesLock.writeLock();

    switch (checkName(customName))
    {
    case nameOk:
        mName = customName;
        names.push_back(mName);
        namesLock.unlock();
        return;
    case nameExists:
        freeInternalName();
        namesLock.unlock();
        throw Poco::ExistsException("setCustomName",
                customName + " already in use");
    case nameBadSyntax:
        freeInternalName();
        namesLock.unlock();
        throw Poco::SyntaxException("setCustomName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

ModuleFactory* Module::parent()
{
    if (mParent)
        return mParent;
    else
        throw Poco::InvalidAccessException("parent",
                "This module has no valid parent factory");
}

#include "Poco/RegularExpression.h"

Module::NameStatus Module::checkName(std::string newName)
{
    // check syntax
    Poco::RegularExpression regex("^[0-9a-zA-Z\\._-]+$");
    if (!regex.match(newName))
        return nameBadSyntax;

    // check existance
    for (std::vector<std::string>::iterator it = names.begin(),
            ite = names.end(); it != ite; it++)
        if (it->compare(newName)==0)
            return nameExists;

    return nameOk;
}

void Module::freeInternalName()
{
    // verify that this is a module creation process
    if (!name().empty())
        return;

    for (std::vector<std::string>::reverse_iterator it = names.rbegin(),
            ite = names.rend(); it != ite; it++ )
    {
        if (it->compare(internalName())==0)
        {
            names.erase((it+1).base());
            return;
        }
    }
}

void Module::run(ModuleTask* pTask)
{
	setRunningTask(pTask);

	taskMngtMutex.lock();
	if (startSyncPending)
	{
		startSyncPending = false;
		taskMngtMutex.unlock();
	}
	taskMngtMutex.unlock();

	try
	{
		if (cancelling)
			throw Poco::RuntimeException(name() +
					": can not run a new task, "
					"the module is cancelling");

		expireOutData();

		setRunningState(ModuleTask::retrievingInDataLocks);

		resetDone = false;
		cancelDone = false;

		int startCond = startCondition();

		mergeTasks(portsWithNewData());

		setRunningState(ModuleTask::processing);
		process(startCond);
	}
	catch (...)
	{
		releaseAllInPorts();
		releaseAllOutPorts();
		throw;
	}

	releaseAllInPorts();
	releaseAllOutPorts();
}

bool Module::sleep(long milliseconds)
{
	if (*runningTask)
		return (*runningTask)->sleep(milliseconds);

	Poco::Thread::sleep(milliseconds);
	return false;
}

bool Module::yield()
{
	if (*runningTask)
		return (*runningTask)->yield();

	Poco::Thread::yield();
	return false;
}

void Module::setProgress(float progress)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setProgress(progress);
}

bool Module::isCancelled()
{
	if (*runningTask == NULL)
		return false;

	return (*runningTask)->isCancelled();
}

InPort* Module::triggingPort()
{
	if (*runningTask)
		return (*runningTask)->triggingPort();

	throw Poco::RuntimeException(name(), "querying trigging port. not in a task");
}

void Module::setRunningState(ModuleTask::RunningStates state)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setRunningState(state);
}

ModuleTask::RunningStates Module::getRunningState()
{
	if (*runningTask == NULL)
		return ModuleTask::processing;

	return (*runningTask)->getRunningState();
}

void Module::enqueueTask(ModuleTask* task)
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex);

	// take ownership of the task.
	Poco::Util::Application::instance()
				             .getSubsystem<ThreadManager>()
				             .registerNewModuleTask(task);

	allTasks.insert(task);
	taskQueue.push_back(task);

	if (taskQueue.size()>1)
	{
		poco_information(logger(), task->name()
					+ ": tasks are already enqueued for " + name());
		return;
	}

	if (!taskIsRunning())
		popTask();
	else
		poco_information(logger(), name() + ": a task is already running");
}

void Module::condCancel()
{
	poco_information(logger(), "Entering Module::condCancel()");

//	if (cancelling || cancelDone)
//		return;

	if (cancelling)
	{
		poco_information(logger(), "already cancelling... return");
		return;
	}

	if (cancelDone)
	{
		poco_information(logger(), "already cancelled... return");
		return;
	}

	cancelling = true;

	poco_information(logger(), "cancelling all module tasks");
	// cancel all module tasks
	taskMngtMutex.lock();
	for (std::set<ModuleTask*>::iterator it = allTasks.begin(),
			ite = allTasks.end(); it != ite; it++)
		(*it)->cancel();
	taskMngtMutex.unlock();

	poco_information(logger(), "cancelling the module itself (specific cancel)");
	cancel();

	poco_information(logger(), "cancel done. ");

	cancelDone = true;
	cancelling = false;
}

void Module::resetWithTargets()
{
	if (reseting || resetDone)
		return;

	reseting = true;

	if (seqRunning())
		condCancel();

	// reset this module
	reset();

	// reset the sequence targets
	resetTargets();

	resetDone = true;
	reseting = false;
}

bool Module::taskIsRunning()
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex); // Ok: recursive mutex

	for (std::set<ModuleTask*>::iterator it = allTasks.begin(),
			ite = allTasks.end(); it != ite; it++)
	{
		switch ((*it)->getState())
		{
		case MergeableTask::TASK_STARTING:
		case MergeableTask::TASK_RUNNING:
			//poco_information(logger(), task->name()
			//		+ ": " + (*it)->name()
			//		+ " is already running for " + name());
			return true;
		case MergeableTask::TASK_FALSE_START:
		case MergeableTask::TASK_IDLE: // probably self
		case MergeableTask::TASK_CANCELLING:
		case MergeableTask::TASK_FINISHED:
			break;
		default:
			poco_bugcheck_msg("unknown task state");
		}
	}

	return false;
}

void Module::popTask()
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex);

	if (taskQueue.empty())
		return;

	ModuleTask* nextTask = taskQueue.front();
	poco_information(logger(), "poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	Poco::Util::Application::instance()
						 .getSubsystem<ThreadManager>()
						 .startModuleTask(nextTask);
}

void Module::popTaskSync()
{
	taskMngtMutex.lock();

	if (taskQueue.empty())
	{
		poco_information(logger(),
			(*runningTask)->name() + ": empty task queue, nothing to sync pop");
		taskMngtMutex.unlock();
		return;
	}

	if (taskIsRunning())
	{
		poco_information(logger(),"sync pop: a task is already running. ");
		taskMngtMutex.unlock();
		return;
	}

	Poco::AutoPtr<ModuleTask> nextTask(taskQueue.front(), true);
	poco_information(logger(), "SYNC poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	startSyncPending = true;

	try
	{
		Poco::Util::Application::instance()
			             .getSubsystem<ThreadManager>()
			             .startSyncModuleTask(nextTask);
	}
	catch (...)
	{
		poco_error(logger(), "can not sync start " + nextTask->name());
		startSyncPending = false;
		taskMngtMutex.unlock();
		throw;
	}
}

void Module::unregisterTask(ModuleTask* task)
{
	Poco::Mutex::ScopedLock lock(taskMngtMutex);
	allTasks.erase(task);
}

void Module::mergeTasks(std::set<size_t> inPortIndexes)
{
	// Poco::FastMutex::ScopedLock lock(taskMngtMutex);
	taskMngtMutex.lock();

	for (std::set<size_t>::iterator it = inPortIndexes.begin(),
			ite = inPortIndexes.end(); it != ite; )
	{
		bool found = false;
		InPort* trigPort;

		try
		{
			trigPort = getInPort(*it);

			if (triggingPort() == trigPort)
			{
				it++;
				continue; // current task
			}

			// seek
			for (std::list<ModuleTask*>::iterator qIt = taskQueue.begin(),
					qIte = taskQueue.end(); qIt != qIte; qIt++)
			{
				poco_information(logger(), "taskQueue includes: " + (*qIt)->name());
				if ((*qIt)->triggingPort() == trigPort)
				{
					found = true;
					(*runningTask)->merge(*qIt);
					taskQueue.erase(qIt);
					poco_information(logger(), "slave task found, merging OK");
					break;
				}
			}
		}
		catch (...)
		{
			taskMngtMutex.unlock();
			throw;
		}

		if (!found)
		{
			taskMngtMutex.unlock();
			poco_warning(logger(),
					"Unable to merge the task for " + trigPort->name()
					+ ". Retry.");
//			if (sleep(500))
			if (yield())
				throw Poco::RuntimeException(name(), "Cancelation upon user request");
			taskMngtMutex.lock();
		}
		else
			it++;
	}

	poco_information(logger(),
		"remaining tasks: " + Poco::NumberFormatter::format(taskQueue.size()));

	taskMngtMutex.unlock();
}
<|endoftext|>


<commit_before>#include "MPC.h"
#include <cppad/cppad.hpp>
#include <cppad/ipopt/solve.hpp>
#include "Eigen-3.3/Eigen/Core"

using CppAD::AD;

// TODO: Set the timestep length and duration
size_t N = 0;
double dt = 0;

// This value assumes the model presented in the classroom is used.
//
// It was obtained by measuring the radius formed by running the vehicle in the
// simulator around in a circle with a constant steering angle and velocity on a
// flat terrain.
//
// Lf was tuned until the the radius formed by the simulating the model
// presented in the classroom matched the previous radius.
//
// This is the length from front to CoG that has a similar radius.
const double Lf = 2.67;

class FG_eval {
 public:
  // Fitted polynomial coefficients
  Eigen::VectorXd coeffs;
  FG_eval(Eigen::VectorXd coeffs) { this->coeffs = coeffs; }

  typedef CPPAD_TESTVECTOR(AD<double>) ADvector;
  void operator()(ADvector& fg, const ADvector& vars) {
    // TODO: implement MPC
    // fg a vector of constraints, x is a vector of constraints.
    // NOTE: You'll probably go back and forth between this function and
    // the Solver function below.
  }
};

//
// MPC class definition implementation.
//
MPC::MPC() {}
MPC::~MPC() {}

vector<double> MPC::Solve(Eigen::VectorXd state, Eigen::VectorXd coeffs) {
  bool ok = true;
  size_t i;
  typedef CPPAD_TESTVECTOR(double) Dvector;

  // TODO: Set the number of model variables (includes both states and inputs).
  // For example: If the state is a 4 element vector, the actuators is a 2
  // element vector and there are 10 timesteps. The number of variables is:
  //
  // 4 * 10 + 2 * 9
  size_t n_vars = 0;
  // TODO: Set the number of constraints
  size_t n_constraints = 0;

  // Initial value of the independent variables.
  // SHOULD BE 0 besides initial state.
  Dvector vars(n_vars);
  for (int i = 0; i < n_vars; i++) {
    vars[i] = 0;
  }

  Dvector vars_lowerbound(n_vars);
  Dvector vars_upperbound(n_vars);
  // TODO: Set lower and upper limits for variables.

  // Lower and upper limits for the constraints
  // Should be 0 besides initial state.
  Dvector constraints_lowerbound(n_constraints);
  Dvector constraints_upperbound(n_constraints);
  for (int i = 0; i < n_constraints; i++) {
    constraints_lowerbound[i] = 0;
    constraints_upperbound[i] = 0;
  }

  // object that computes objective and constraints
  FG_eval fg_eval(coeffs);

  //
  // NOTE: You don't have to worry about these options
  //
  // options for IPOPT solver
  std::string options;
  // Uncomment this if you'd like more print information
  options += "Integer print_level  0\n";
  // NOTE: Setting sparse to true allows the solver to take advantage
  // of sparse routines, this makes the computation MUCH FASTER. If you
  // can uncomment 1 of these and see if it makes a difference or not but
  // if you uncomment both the computation time should go up in orders of
  // magnitude.
  options += "Sparse  true        forward\n";
  options += "Sparse  true        reverse\n";
  // NOTE: Currently the solver has a maximum time limit of 0.5 seconds.
  // Change this as you see fit.
  options += "Numeric max_cpu_time          0.5\n";

  // place to return solution
  CppAD::ipopt::solve_result<Dvector> solution;

  // solve the problem
  CppAD::ipopt::solve<Dvector, FG_eval>(
      options, vars, vars_lowerbound, vars_upperbound, constraints_lowerbound,
      constraints_upperbound, fg_eval, solution);

  // Check some of the solution values
  ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;

  // Cost
  auto cost = solution.obj_value;
  std::cout << "Cost " << cost << std::endl;

  // TODO: Return the first actuator values. The variables can be accessed with
  // `solution.x[i]`.
  //
  // {...} is shorthand for creating a vector, so auto x1 = {1.0,2.0}
  // creates a 2 element double vector.
  return {};
}
<commit_msg>Delete MPC.cpp<commit_after><|endoftext|>