This is indent.c in view mode; [Download] [Up]
/*
* Copyright (c) 1995 John E. Davis (davis@space.mit.edu)
* All Rights Reserved.
*/
#include <config.h>
#include <stdio.h>
#include <string.h>
#include "buffer.h"
#include "window.h"
#include "misc.h"
#include "cmds.h"
#include "display.h"
#include "ledit.h"
#include "screen.h"
#include "sysdep.h"
static Syntax_Table_Type *Syntax_Tables;
static void goto_effective_eol (Syntax_Table_Type *table)
{
unsigned char *p, *pmax;
unsigned short *syntax;
register unsigned char ch;
unsigned char in_char = 0;
int cb0, cb1, quote, sc, cc;
cb0 = table->comment_beg;
quote = table->quote_char;
sc = table->string_char;
cc = table->char_char;
syntax = table->char_syntax;
if (table->flags & MULTICHAR_TYPE) cb1 = table->comment_beg2;
else cb1 = -1;
p = CLine->data;
pmax = CLine->data + CLine->len;
while (p < pmax)
{
ch = *p++;
if ((syntax[ch] & SYNTAX_MASK) == 0) continue;
if ((in_char == 0) && (ch == cb0))
{
if (cb1 != -1)
{
if ((p < pmax) && (*p != cb1)) continue;
p--;
}
p -= 2;
Point = (int) (p - CLine->data);
/* Note: it is ok if Point is negative here. */
return;
}
if (ch == quote)
{
p++;
continue;
}
if (ch == in_char) in_char = 0;
else if (in_char == 0)
{
if (ch == sc) in_char = sc;
if (ch == cc) in_char = cc;
}
}
Point = CLine->len - 1;
}
Syntax_Table_Type *Default_Syntax_Table;
/* Go backward looking for the matching ch--- not the char that matches ch.
* Rather, ch is the matching character.
* This routine returns:
* 1 if found and leaves the point on the match
* -2 if not found but we appear to be in a comment. In this case, the point
* if left at the beginning of the comment
* -1 Not found but we appear to be in a string. This leaves the point at the
* beginning of the string.
* 0 if not found. The point is left where we gave up
* 2 if went back too far
* count is the number of lines to go back
*/
static int backward_goto_match (int count, unsigned char ch)
{
unsigned char *p, *pmin, *save_pos = NULL, want_ch;
unsigned short *syntax;
int in_string, in_comment, level, is_quoted;
int cb, ce, ce0, cb0, quote, flags;
Syntax_Table_Type *table;
unsigned int this_syntax;
p = CLine->data + Point;
table = CBuf->syntax_table;
if (table == NULL) return 0;
syntax = table->char_syntax;
quote = table->quote_char;
flags = table->flags;
if (flags & MULTICHAR_TYPE)
{
cb = table->comment_beg2;
ce = table->comment_end2;
cb0 = table->comment_beg;
ce0 = table->comment_end;
}
else
{
cb = table->comment_beg;
ce = table->comment_end;
cb0 = -1;
ce0 = -1;
}
/* Here we go */
if (ch == 0) ch = *p;
want_ch = table->matching_delim [ch];
if (want_ch == 0) return 0;
level = 1;
in_string = 0; in_comment = 0;
Point--;
while (count)
{
p = CLine->data + Point;
pmin = CLine->data;
/* This loop here is where it all happens. */
while (p >= pmin)
{
ch = *p--;
if ((syntax[ch] & SYNTAX_MASK) == 0) continue;
/* Check to see if it is quoted. */
if ((p >= pmin) && (*p == quote))
{
unsigned char *psave;
is_quoted = 0;
psave = p;
while ((p >= pmin) && (*p == quote))
{
p--;
is_quoted = !is_quoted;
}
if (is_quoted) continue;
p = psave;
}
this_syntax = syntax[ch];
if (this_syntax & COMMENT_SYNTAX)
{
if (in_string && !in_comment) continue;
if (in_comment == 0)
{
if (ch == ce)
{
if (ce0 != -1)
{
if ((p >= pmin) && (*p == ce0))
{
in_comment = 1;
p--;
}
}
else in_comment = 1;
}
if (in_comment) continue;
}
if (ch == cb)
{
/* if we hit a comment start, we are out of
* here since there is no point in parsing beyond
* because there are no syntax contraints within a
* comment.
*/
if (cb0 != -1)
{
if ((p >= pmin) && (*p == cb0))
{
in_comment--;
p--;
}
else goto comment_endif;
}
else in_comment--;
if (in_comment || in_string)
{
p++;
Point = (int) (p - pmin);
return -2;
}
continue;
}
}
comment_endif:
if (this_syntax & STRING_SYNTAX)
{
/* string/char */
if (in_comment) continue;
if (in_string == 0) in_string = ch;
else if (in_string == ch) in_string = 0;
/* Save this in case we are really in a comment
* because if we do not find the other match, we
* must come back again. Sigh.
*/
if (in_string) save_pos = p;
continue;
}
if (this_syntax & OPEN_DELIM_SYNTAX)
{
/* opening delimiter */
if (in_string || in_comment) continue;
if (level == 1)
{
Point = (int) (p - pmin) + 1;
if (ch == want_ch) return 1;
return 0;
}
level--;
}
if (this_syntax & CLOSE_DELIM_SYNTAX)
{
if (!in_string && !in_comment) level++;
}
}
/* END OF MAIN LOOP: while (p >= pmin) */
if (in_string && !in_comment)
{
/* Ok so we have several choices. Here I am going to assume
* that we are in a comment unless there is a quote char at the
* end of the previous line to indicate a continuation.
*/
if ((CLine->prev == NULL)
|| (CLine->prev->len <= 1)
|| (quote != *(CLine->prev->data + (CLine->prev->len - 2))))
{
/*
* Do the same for the current line since it is possible
* for the quote at the end of the line to indicate that
* the string char is really the beginning.
*/
if ((CLine->len <= 1)
|| (quote != *(CLine->data + (CLine->len - 2))))
{
in_comment = 1;
}
/* So we have a quote at the end of this line. So,
* instead of assuming a comment, let's assume that we
* are really back in code again.
*/
else in_string = 0;
/* go back and try again under new assumption */
Point = (int) (save_pos - CLine->data);
continue;
}
}
/* Move to the previous line. */
if (CLine->prev == NULL)
{
Point = 0;
break;
}
CLine = CLine->prev; LineNum--; Point = CLine->len - 1;
count--;
/* Compute the effective end of line since we do not want to
* start out in a comment. This only happens for eol type comments.
* This means the the Point is now in a position to continue parsing
* from. It is possible that Point is negative after this call meaning
* that the comment started at the beginning of the line.
*/
if (flags & EOL_COMMENT_TYPE)
goto_effective_eol (table);
}
/* What have we learned? */
if (Point < 0) Point = 0;
if (count == 0)
{
/* In this case, we went back as far as permitted. Nothing much can be
* said.
*/
Point = 0;
return 2;
}
if (in_string) return -1;
if (in_comment) return -2;
/* If we are here, then we have a mismatch */
return 0;
}
static int forward_goto_match (unsigned char ch)
{
unsigned char *p, *pmax, want_ch;
unsigned short *syntax;
int in_string, in_comment, level;
int cb, ce, ce1, cb1, flags;
unsigned int this_syntax;
Syntax_Table_Type *table;
p = CLine->data + Point;
table = CBuf->syntax_table;
if (table == NULL) return 0;
syntax = table->char_syntax;
flags = table->flags;
if (flags & MULTICHAR_TYPE)
{
cb1 = table->comment_beg2;
ce1 = table->comment_end2;
cb = table->comment_beg;
ce = table->comment_end;
}
else
{
cb = table->comment_beg;
ce = table->comment_end;
cb1 = -1;
ce1 = -1;
}
/* Here we go */
if (ch == 0) ch = *p;
want_ch = table->matching_delim [ch];
if (want_ch == 0) return 0;
level = 1;
in_string = 0; in_comment = 0;
Point++;
while (1) /* The only way to get out of
* this loop is to find a match.
*/
{
p = CLine->data + Point;
pmax = CLine->data + CLine->len;
/* This loop here is where it all happens. */
while (p < pmax)
{
ch = *p++;
if ((syntax[ch] & SYNTAX_MASK) == 0) continue;
this_syntax = syntax[ch];
if (this_syntax & COMMENT_SYNTAX)
{
if (in_string) continue;
if (in_comment)
{
if (ch == ce)
{
if (ce1 != -1)
{
if ((p < pmax) && (*p == ce1))
{
in_comment = 0;
p++;
}
}
else in_comment = 0;
}
if (in_comment == 0) continue;
}
else if (ch == cb) /* not in comment */
{
if (cb1 != -1)
{
if ((p < pmax) && (*p == cb1))
{
in_comment = 1;
p++;
}
}
else in_comment = 1;
if (in_comment && (flags & EOL_COMMENT_TYPE))
{
/* This will need modified once I support two
* types of comments, e.g., C++ (yuk)
*/
p = pmax;
in_comment = 0;
}
if (in_comment) continue;
}
}
if (this_syntax & STRING_SYNTAX)
{
/* string/char */
if (in_comment) continue;
if (in_string == 0) in_string = ch;
else if (in_string == ch) in_string = 0;
continue;
}
if (this_syntax & OPEN_DELIM_SYNTAX)
{
if (!in_string && !in_comment) level++;
continue;
}
if (this_syntax & CLOSE_DELIM_SYNTAX)
{
if (in_string || in_comment) continue;
if (level == 1)
{
Point = (int) (p - CLine->data) - 1;
if (ch == want_ch) return 1;
return 0;
}
level--;
continue;
}
if (this_syntax & QUOTE_SYNTAX) p++; /* skip next char */
}
/* END OF MAIN LOOP: while (p < pmax) */
/* Move to the next line. */
if (CLine->next == NULL) break;
CLine = CLine->next; LineNum++; Point = 0;
}
eol ();
if (in_string) return -1;
if (in_comment) return -2;
/* If we are here, then we have a mismatch */
return 0;
}
int find_matching_delimiter (int *ch)
{
unsigned char ch1 = (unsigned char) *ch;
Syntax_Table_Type *table = CBuf->syntax_table;
if (ch1 == 0) ch1 = *(CLine->data + Point);
if (table->char_syntax[ch1] & OPEN_DELIM_SYNTAX)
return forward_goto_match (ch1);
else return backward_goto_match (5000, ch1);
}
int goto_match (void)
{
unsigned char ch;
int ret;
Syntax_Table_Type *table = CBuf->syntax_table;
ch = *(CLine->data + Point);
if (table->char_syntax[ch] & OPEN_DELIM_SYNTAX)
ret = forward_goto_match (ch);
else ret = backward_goto_match (LineNum, ch);
if (ret != 1)
{
if (!IS_MINIBUFFER) msg_error("Mismatch!!");
return (0);
}
return (1);
}
static int parse_to_point1 (Syntax_Table_Type *table)
{
unsigned char *p, *pmax, ch;
unsigned char in_char = 0, in_comm = 0;
int cb0, cb1, ce0, ce1, quote, sc, cc, flags;
sc = table->string_char;
cc = table->char_char;
flags = table->flags;
if (flags & MULTICHAR_TYPE)
{
cb0 = table->comment_beg;
ce0 = table->comment_end;
cb1 = table->comment_beg2;
ce1 = table->comment_end2;
}
else
{
cb0 = table->comment_beg;
ce0 = table->comment_end;
cb1 = ce1 = -1;
}
quote = table->quote_char;
p = CLine->data;
pmax = p + Point;
while (p < pmax)
{
ch = *p++;
if (in_comm)
{
if (ch == ce0)
{
if (ce1 == -1) in_comm = 0;
else if ((p < pmax) && (*p == ce1))
{
in_comm = 0;
p++;
}
}
if (in_comm) continue;
}
if (in_char)
{
if (ch == in_char) in_char = 0;
else if (ch == quote) p++;
continue;
}
if (ch == cb0)
{
if (cb1 == -1) in_comm = 1;
else if ((p < pmax) && (*p == cb1))
{
in_comm = 1;
p++;
}
if (in_comm) continue;
}
if ((ch == cc) || (ch == sc)) in_char = ch;
}
if (in_char) return -1;
if (in_comm) return -2;
return 0;
}
int parse_to_point (void)
{
Syntax_Table_Type *table = CBuf->syntax_table;
if (table == NULL) return 0;
return parse_to_point1 (table);
}
/* blink the matching fence. This assumes that the window is ok */
void blink_match (void)
{
Line *save;
int pnt, code, matchp;
unsigned int l;
char buf[600], strbuf[256];
if (!Blink_Flag || (Repeat_Factor != NULL) || Batch) return;
if (JWindow->trashed) update((Line *) NULL, 0, 0);
if (JWindow->trashed) return;
pnt = Point;
save = CLine;
l = LineNum;
if (Point) Point--;
code = backward_goto_match (1000, 0);
if (code == 0)
{
if ((! (CBuf->modes == WRAP_MODE)) && (!IS_MINIBUFFER))
message("Mismatch??");
}
else if ((code == 1) && is_line_visible (LineNum))
{
point_cursor(0);
input_pending(&Number_Ten);
Point = pnt;
CLine = save;
LineNum = l;
point_cursor(0);
return;
}
else if (code == 1)
{
matchp = Point;
Point = 0;
strcpy(buf, "Matches ");
skip_whitespace();
if ((matchp == Point) && prevline(&Number_One))
{
Point = 0;
strcat(buf, make_line_string(strbuf));
nextline(&Number_One);
Point = 0;
}
strcat(buf, make_line_string(strbuf));
message(buf);
}
Point = pnt;
CLine = save;
LineNum = l;
}
static Syntax_Table_Type *find_syntax_table (char *name, int err)
{
Syntax_Table_Type *table = Syntax_Tables;
while (table != NULL)
{
if (!strncmp (table->name, name, 15)) return table;
table = table->next;
}
if (err) msg_error ("Syntax table undefined.");
return table;
}
void set_syntax_flags (char *name, int *flags)
{
Syntax_Table_Type *table;
table = find_syntax_table (name, 1);
if (table == NULL) return;
table->flags |= *flags & 0xFF;
}
void define_syntax (int *what, char *name)
{
Syntax_Table_Type *table;
int c1, c2, i;
char *s1 = NULL, *s2 = NULL;
unsigned char lut[256], *s;
table = find_syntax_table (name, 1);
if (table == NULL) return;
switch (*what)
{
case '%':
if (SLang_pop_string (&s2, &c2)) break;
if (SLang_pop_string (&s1, &c1)) break;
table->char_syntax[(unsigned char) *s2] |= COMMENT_SYNTAX;
if (0 != (table->comment_end = (unsigned char) *s2))
{
table->comment_end2 = (unsigned char) *(s2 + 1);
table->char_syntax[(unsigned char) *(s2 + 1)] |= COMMENT_SYNTAX;
}
table->char_syntax[(unsigned char) *s1] |= COMMENT_SYNTAX;
if (0 != (table->comment_beg = (unsigned char) *s1))
{
table->comment_beg2 = (unsigned char) *(s1 + 1);
table->char_syntax[(unsigned char) *(s1 + 1)] |= COMMENT_SYNTAX;
}
if (table->comment_beg2) table->flags |= MULTICHAR_TYPE;
if ((table->comment_end == 0)
|| (table->comment_end == '\n'))
table->flags |= EOL_COMMENT_TYPE;
break;
case '\\':
if (SLang_pop_integer (&c2)) break;
table->char_syntax[(unsigned char) c2] |= QUOTE_SYNTAX;
table->quote_char = (unsigned char) c2;
break;
case '#':
if (SLang_pop_integer (&c2)) break;
table->preprocess = (unsigned char) c2;
break;
case '\'':
if (SLang_pop_integer (&c2)) break;
table->char_syntax[(unsigned char) c2] |= STRING_SYNTAX;
table->char_char = (unsigned char) c2;
break;
case '"':
if (SLang_pop_integer (&c2)) break;
table->char_syntax[(unsigned char) c2] |= STRING_SYNTAX;
table->string_char = (unsigned char) c2;
break;
case '<':
case '>':
if (SLang_pop_string (&s1, &c1)) break;
s2 = s1;
while (*s2 != 0)
{
if (*(s2 + 1) == 0) break;
table->char_syntax[(unsigned char) *s2] |= HTML_START_SYNTAX;
table->char_syntax[(unsigned char) *(s2 + 1)] |= HTML_END_SYNTAX;
s2 += 2;
}
s2 = NULL;
break;
case '(':
case ')':
if (SLang_pop_string (&s2, &c2)) break;
if (SLang_pop_string (&s1, &c1)) break;
i = strlen (s1);
if (i != strlen (s2))
{
msg_error ("Delimiter set does not match.");
}
while (i > 0)
{
unsigned char ch1, ch2;
i--;
ch1 = (unsigned char) s1[i]; ch2 = (unsigned char) s2[i];
table->char_syntax[ch1] |= OPEN_DELIM_SYNTAX;
table->char_syntax[ch2] |= CLOSE_DELIM_SYNTAX;
table->matching_delim[ch2] = ch1;
table->matching_delim[ch1] = ch2;
}
break;
case '+':
if (SLang_pop_string (&s1, &c1)) break;
for (i = 0; i < 256; i++) table->char_syntax[i] &= ~OP_SYNTAX;
s = (unsigned char *) s1;
while (*s)
{
table->char_syntax[*s] |= OP_SYNTAX;
s++;
}
break;
case '0':
if (SLang_pop_string (&s1, &c1)) break;
SLmake_lut (lut, (unsigned char *) s1, 0);
for (i = 0; i < 256; i++)
{
if (lut[i]) table->char_syntax[i] |= NUMBER_SYNTAX;
else table->char_syntax[i] &= ~NUMBER_SYNTAX;
}
break;
case ',':
if (SLang_pop_string (&s1, &c1)) break;
s = (unsigned char *) s1;
for (i = 0; i < 256; i++) table->char_syntax[i] &= ~DELIM_SYNTAX;
while (*s)
{
table->char_syntax[*s] |= DELIM_SYNTAX;
s++;
}
break;
case 'w':
if (SLang_pop_string (&s1, &c1)) break;
SLmake_lut (lut, (unsigned char *) s1, 0);
for (i = 0; i < 256; i++)
{
if (lut[i]) table->char_syntax[i] |= WORD_SYNTAX;
else table->char_syntax[i] &= ~WORD_SYNTAX;
}
break;
default:
msg_error ("Bad parameter to define_syntax");
}
if ((s1 != NULL) && c1) SLFREE (s1);
if ((s2 != NULL) && c2) SLFREE (s2);
}
void use_syntax_table (char *s)
{
Syntax_Table_Type *table = find_syntax_table (s, 1);
if (table == NULL) return;
CBuf->syntax_table = table;
}
void create_syntax_table (char *name)
{
Syntax_Table_Type *table;
if (NULL != find_syntax_table (name, 0)) return;
if (NULL == (table = (Syntax_Table_Type *) SLMALLOC(sizeof (Syntax_Table_Type))))
{
SLang_Error = SL_MALLOC_ERROR;
return;
}
MEMSET ((char *) table, 0, sizeof (Syntax_Table_Type));
table->next = Syntax_Tables;
Syntax_Tables = table;
strncpy (table->name, name, 15);
table->name[15] = 0;
}
void init_syntax_tables (void)
{
unsigned short *a;
unsigned char *m;
Default_Syntax_Table = (Syntax_Table_Type *) SLMALLOC (sizeof (Syntax_Table_Type));
if (Default_Syntax_Table == NULL) return;
MEMSET ((char *) Default_Syntax_Table, 0, sizeof (Syntax_Table_Type));
a = Default_Syntax_Table->char_syntax;
m = Default_Syntax_Table->matching_delim;
a [(unsigned char) '['] = OPEN_DELIM_SYNTAX; m[(unsigned char) '['] = ']';
a [(unsigned char) ']'] = CLOSE_DELIM_SYNTAX; m[(unsigned char) ']'] = '[';
a [(unsigned char) '('] = OPEN_DELIM_SYNTAX; m[(unsigned char) '('] = ')';
a [(unsigned char) ')'] = CLOSE_DELIM_SYNTAX; m[(unsigned char) ')'] = '(';
a [(unsigned char) '{'] = OPEN_DELIM_SYNTAX; m[(unsigned char) '{'] = '}';
a [(unsigned char) '}'] = CLOSE_DELIM_SYNTAX; m[(unsigned char) '}'] = '{';
}
void define_keywords (char *name, char *kwords, int *lenp, int *tbl_nump)
{
char *kw;
int len;
int kwlen;
unsigned int table_number = (unsigned int) *tbl_nump;
Syntax_Table_Type *table = find_syntax_table (name, 1);
if (table == NULL) return;
if (table_number >= MAX_KEYWORD_TABLES)
{
msg_error ("Table number too high.");
return;
}
len = *lenp;
if ((len < 1) || (len > MAX_KEYWORD_LEN))
{
msg_error ("Keyword length not supported.");
return;
}
kwlen = strlen (kwords);
if (kwlen % len)
{
msg_error ("Keyword list is improperly formed.");
return;
}
len--;
kw = table->keywords[table_number][len];
if (kw == NULL) SLang_push_string ("");
else SLang_push_malloced_string (kw);
kw = (char *) SLMALLOC (kwlen + 1);
if (kw == NULL)
{
SLang_Error = SL_MALLOC_ERROR;
return;
}
strcpy (kw, kwords);
table->keywords[table_number][len] = kw;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.