001: /*
002: * AutoconfFormatter.java
003: *
004: * Copyright (C) 2000-2003 Peter Graves
005: * $Id: AutoconfFormatter.java,v 1.2 2003/10/21 18:30:01 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: public final class AutoconfFormatter extends Formatter {
025: private static final int STATE_BACKQUOTE = STATE_LAST + 1;
026:
027: // Formats.
028: private static final int AUTOCONF_FORMAT_TEXT = 0;
029: private static final int AUTOCONF_FORMAT_COMMENT = 1;
030: private static final int AUTOCONF_FORMAT_STRING = 2;
031: private static final int AUTOCONF_FORMAT_KEYWORD = 3;
032: private static final int AUTOCONF_FORMAT_FUNCTION = 4;
033:
034: private static StringSet keywords;
035: private static StringSet functions;
036:
037: private FastStringBuffer sb = new FastStringBuffer();
038: private String token;
039:
040: public AutoconfFormatter(Buffer buffer) {
041: this .buffer = buffer;
042: if (functions == null)
043: functions = new StringSet(autoconfFunctions);
044: }
045:
046: public LineSegmentList formatLine(Line line) {
047: clearSegmentList();
048: if (line == null || line.length() == 0) {
049: addSegment("", AUTOCONF_FORMAT_TEXT);
050: return segmentList;
051: }
052: parseLine(line);
053: for (int i = 0; i < segmentList.size(); i++) {
054: LineSegment segment = segmentList.getSegment(i);
055: if (segment.getFormat() >= 0)
056: continue;
057: String s = segment.getText();
058: if (isKeyword(s))
059: segment.setFormat(AUTOCONF_FORMAT_KEYWORD);
060: else if (isFunction(s))
061: segment.setFormat(AUTOCONF_FORMAT_FUNCTION);
062: else
063: segment.setFormat(AUTOCONF_FORMAT_TEXT);
064: }
065: return segmentList;
066: }
067:
068: private void endToken(int state) {
069: if (sb.length() > 0) {
070: int format = -1;
071: switch (state) {
072: case STATE_NEUTRAL:
073: break;
074: case STATE_QUOTE:
075: case STATE_BACKQUOTE:
076: format = AUTOCONF_FORMAT_STRING;
077: break;
078: case STATE_IDENTIFIER:
079: break;
080: case STATE_COMMENT:
081: format = AUTOCONF_FORMAT_COMMENT;
082: break;
083: }
084: token = sb.toString();
085: addSegment(token, format);
086: sb.setLength(0);
087: }
088: }
089:
090: private void parseLine(Line line) {
091: String text = line.getText();
092: if (Editor.tabsAreVisible())
093: text = Utilities
094: .makeTabsVisible(text, buffer.getTabWidth());
095: else
096: text = Utilities.detab(text, buffer.getTabWidth());
097: sb.setLength(0);
098: int i = 0;
099: int state = STATE_NEUTRAL;
100: final int limit = text.length();
101: // Skip whitespace at start of line.
102: while (i < limit) {
103: char c = text.charAt(i);
104: if (Character.isWhitespace(c)) {
105: sb.append(c);
106: ++i;
107: } else {
108: endToken(state);
109: break;
110: }
111: }
112: while (i < limit) {
113: char c = text.charAt(i);
114: if (state == STATE_QUOTE) {
115: if (c == '"') {
116: sb.append(c);
117: endToken(state);
118: state = STATE_NEUTRAL;
119: } else {
120: sb.append(c);
121:
122: if (c == '\\' && i < limit - 1) {
123: // Escape char.
124: sb.append(text.charAt(++i));
125: }
126: }
127: ++i;
128: continue;
129: }
130: if (state == STATE_BACKQUOTE) {
131: sb.append(c);
132: if (c == '`') {
133: endToken(state);
134: state = STATE_NEUTRAL;
135: }
136: ++i;
137: continue;
138: }
139: // Reaching here, we're not in a quoted string.
140: if (c == '\\') {
141: // Escape.
142: sb.append(c);
143: if (++i < limit) {
144: sb.append(text.charAt(i));
145: ++i;
146: }
147: continue;
148: }
149: if (c == '"') {
150: endToken(state);
151: sb.append(c);
152: state = STATE_QUOTE;
153: ++i;
154: continue;
155: }
156: if (c == '`') {
157: endToken(state);
158: sb.append(c);
159: state = STATE_BACKQUOTE;
160: ++i;
161: continue;
162: }
163: if (state == STATE_IDENTIFIER) {
164: if (buffer.mode.isIdentifierPart(c))
165: sb.append(c);
166: else {
167: // End of identifier.
168: endToken(state);
169: if (token.equals("dnl")) {
170: state = STATE_COMMENT;
171: sb.append(text.substring(i));
172: endToken(state);
173: return;
174: }
175: state = STATE_NEUTRAL;
176: sb.append(c);
177: }
178: ++i;
179: continue;
180: }
181: if (state == STATE_NEUTRAL) {
182: if (c == '#') {
183: boolean isComment = false;
184: if (i == limit - 1) {
185: // '#' is last or only character.
186: isComment = true;
187: } else {
188: // Ignore "#include", "#define", etc. (AC_TRY_COMPILE)
189: char nextChar = text.charAt(i + 1);
190: if (nextChar == ' ' || nextChar == '\t'
191: || nextChar == '#' || nextChar == '!')
192: isComment = true;
193: }
194: if (isComment) {
195: state = STATE_COMMENT;
196: sb.append(text.substring(i));
197: endToken(state);
198: return; // We're finished with this line.
199: }
200: // Not really the start of a comment.
201: sb.append(c);
202: } else if (buffer.mode.isIdentifierStart(c)) {
203: endToken(state);
204: sb.append(c);
205: state = STATE_IDENTIFIER;
206: } else
207: // Still neutral...
208: sb.append(c);
209: }
210: ++i;
211: }
212: endToken(state);
213: }
214:
215: public FormatTable getFormatTable() {
216: if (formatTable == null) {
217: formatTable = new FormatTable("AutoconfMode");
218: formatTable.addEntryFromPrefs(AUTOCONF_FORMAT_TEXT, "text");
219: formatTable.addEntryFromPrefs(AUTOCONF_FORMAT_COMMENT,
220: "comment");
221: formatTable.addEntryFromPrefs(AUTOCONF_FORMAT_STRING,
222: "string");
223: formatTable.addEntryFromPrefs(AUTOCONF_FORMAT_KEYWORD,
224: "keyword");
225: formatTable.addEntryFromPrefs(AUTOCONF_FORMAT_FUNCTION,
226: "function");
227: }
228: return formatTable;
229: }
230:
231: private final boolean isFunction(String s) {
232: if (functions == null)
233: return false;
234: return functions.contains(s);
235: }
236:
237: private static final String[] autoconfFunctions = { "AC_AIX",
238: "AC_ALLOCA", "AC_ARG_ARRAY", "AC_ARG_ENABLE",
239: "AC_ARG_PROGRAM", "AC_ARG_WITH", "AC_BEFORE",
240: "AC_C_BIGENDIAN", "AC_C_CHAR_UNSIGNED", "AC_C_CONST",
241: "AC_C_CROSS", "AC_C_INLINE", "AC_C_LONG_DOUBLE",
242: "AC_C_STRINGIZE", "AC_CACHE_CHECK", "AC_CACHE_LOAD",
243: "AC_CACHE_SAVE", "AC_CACHE_VAL", "AC_CANONICAL_HOST",
244: "AC_CANONICAL_SYSTEM", "AC_CHAR_UNSIGNED", "AC_CHECK_FILE",
245: "AC_CHECK_FILES", "AC_CHECK_FUNC", "AC_CHECK_FUNCS",
246: "AC_CHECK_HEADER", "AC_CHECK_HEADERS", "AC_CHECK_LIB",
247: "AC_CHECK_PROG", "AC_CHECK_PROGS", "AC_CHECK_SIZEOF",
248: "AC_CHECK_TOOL", "AC_CHECK_TYPE", "AC_CHECKING",
249: "AC_COMPILE_CHECK", "AC_CONFIG_AUX_DIR",
250: "AC_CONFIG_COMMANDS", "AC_CONFIG_FILES",
251: "AC_CONFIG_HEADER", "AC_CONFIG_SUBDIRS", "AC_CONST",
252: "AC_CROSS_CHECK", "AC_CYGWIN", "AC_DECL_SYS_SIGLIST",
253: "AC_DECL_YYTEXT", "AC_DEFINE", "AC_DEFINE_UNQUOTED",
254: "AC_DEFUN", "AC_DIR_HEADER", "AC_DYNIX_SEQ",
255: "AC_EGREP_CPP", "AC_EGREP_HEADER", "AC_ENABLE", "AC_ERROR",
256: "AC_EXEEXT", "AC_F77_LIBRARY_LDFLAGS", "AC_FIND_X",
257: "AC_FIND_XTRA", "AC_FUNC_ALLOCA", "AC_FUNC_CHECK",
258: "AC_FUNC_CLOSEDIR_VOID", "AC_FUNC_FNMATCH",
259: "AC_FUNC_GETLOADAVG", "AC_FUNC_GETMNTENT",
260: "AC_FUNC_GETPGRP", "AC_FUNC_MEMCMP", "AC_FUNC_MMAP",
261: "AC_FUNC_SELECT_ARGTYPES", "AC_FUNC_SETPGRP",
262: "AC_FUNC_SETVBUF_REVERSED", "AC_FUNC_STRCOLL",
263: "AC_FUNC_STRFTIME", "AC_FUNC_UTIME_NULL", "AC_FUNC_VFORK",
264: "AC_FUNC_VPRINTF", "AC_FUNC_WAIT3", "AC_GCC_TRADITIONAL",
265: "AC_GETGROUPS_T", "AC_GETLOADAVG", "AC_HAVE_FUNCS",
266: "AC_HAVE_HEADERS", "AC_HAVE_LIBRARY", "AC_HAVE_POUNDBANG",
267: "AC_HEADER_CHECK", "AC_HEADER_DIRENT", "AC_HEADER_EGREP",
268: "AC_HEADER_MAJOR", "AC_HEADER_STAT", "AC_HEADER_STDC",
269: "AC_HEADER_SYS_WAIT", "AC_HEADER_TIME", "AC_INIT",
270: "AC_INLINE", "AC_INT_16_BITS", "AC_IRIX_SUN",
271: "AC_ISC_POSIX", "AC_LANG_C", "AC_LANG_CPLUSPLUS",
272: "AC_LANG_FORTRAN77", "AC_LANG_RESTORE", "AC_LANG_SAVE",
273: "AC_LINK_FILES", "AC_LN_S", "AC_LONG_64_BITS",
274: "AC_LONG_DOUBLE", "AC_LONG_FILE_NAMES", "AC_MAJOR_HEADER",
275: "AC_MEMORY_H", "AC_MINGW32", "AC_MINIX",
276: "AC_MINUS_C_MINUS_O", "AC_MMAP", "AC_MODE_T",
277: "AC_MSG_CHECKING", "AC_MSG_ERROR", "AC_MSG_RESULT",
278: "AC_MSG_WARN", "AC_OBJEXT", "AC_OBSOLETE", "AC_OFF_T",
279: "AC_OUTPUT", "AC_OUTPUT_COMMANDS", "AC_PATH_PROG",
280: "AC_PATH_PROGS", "AC_PATH_X", "AC_PATH_XTRA", "AC_PID_T",
281: "AC_PREFIX", "AC_PREFIX_PROGRAM", "AC_PREREQ",
282: "AC_PROG_AWK", "AC_PROG_CC", "AC_PROG_CC_C_O",
283: "AC_PROG_CPP", "AC_PROG_CXX", "AC_PROG_CXXCPP",
284: "AC_PROG_F77_C_O", "AC_PROG_FORTRAN",
285: "AC_PROG_GCC_TRADITIONAL", "AC_PROG_INSTALL",
286: "AC_PROG_LEX", "AC_PROG_LN_S", "AC_PROG_MAKE_SET",
287: "AC_PROG_RANLIB", "AC_PROG_YACC", "AC_PROGRAM_CHECK",
288: "AC_PROGRAM_EGREP", "AC_PROGRAM_PATH", "AC_PROGRAMS_CHECK",
289: "AC_PROGRAMS_PATH", "AC_PROVIDE", "AC_REMOTE_TAPE",
290: "AC_REPLACE_FUNCS", "AC_REQUIRE", "AC_REQUIRE_CPP",
291: "AC_RESTARTABLE_SYSCALLS", "AC_RETSIGTYPE", "AC_REVISION",
292: "AC_RSH", "AC_SCO_INTL", "AC_SEARCH_LIBS", "AC_SET_MAKE",
293: "AC_SETVBUF_REVERSED", "AC_SIZE_T", "AC_SIZEOF_TYPE",
294: "AC_ST_BLKSIZE", "AC_ST_BLOCKS", "AC_ST_RDEV",
295: "AC_STAT_MACROS_BROKEN", "AC_STDC_HEADERS", "AC_STRCOLL",
296: "AC_STRUCT_ST_BLKSIZE", "AC_STRUCT_ST_BLOCKS",
297: "AC_STRUCT_ST_RDEV", "AC_STRUCT_TIMEZONE", "AC_STRUCT_TM",
298: "AC_SUBST", "AC_SUBST_FILE", "AC_SYS_INTERPRETER",
299: "AC_SYS_LONG_FILE_NAMES", "AC_SYS_RESTARTABLE_SYSCALLS",
300: "AC_SYS_SIGLIST_DECLARED", "AC_TEST_CPP",
301: "AC_TEST_PROGRAM", "AC_TIME_WITH_SYS_TIME", "AC_TIMEZONE",
302: "AC_TRY_COMPILE", "AC_TRY_CPP", "AC_TRY_LINK",
303: "AC_TRY_LINK_FUNC", "AC_TRY_RUN", "AC_TYPE_GETGROUPS",
304: "AC_TYPE_MODE_T", "AC_TYPE_OFF_T", "AC_TYPE_PID_T",
305: "AC_TYPE_SIGNAL", "AC_TYPE_SIZE_T", "AC_TYPE_UID_T",
306: "AC_UID_T", "AC_UNISTD_H", "AC_USG", "AC_UTIME_NULL",
307: "AC_VALIDATE_CACHED_SYSTEM_TUPLE", "AC_VERBOSE",
308: "AC_VFORK", "AC_VPRINTF", "AC_WAIT3", "AC_WARN", "AC_WITH",
309: "AC_WORDS_BIGENDIAN", "AC_XENIX_DIR", "AC_YYTEXT_POINTER",
310:
311: // Automake.
312: "AM_CONDITIONAL", "AM_CONFIG_HEADER", "AM_INIT_AUTOMAKE",
313: "AM_MAINTAINER_MODE", };
314: }
|