/[jscoverage]/trunk/highlight.c
ViewVC logotype

Diff of /trunk/highlight.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 179 by siliconforks, Sun Sep 21 18:35:21 2008 UTC revision 213 by siliconforks, Fri Oct 3 02:25:47 2008 UTC
# Line 21  Line 21 
21    
22  #include "highlight.h"  #include "highlight.h"
23    
24    #include <assert.h>
25  #include <stdlib.h>  #include <stdlib.h>
26  #include <string.h>  #include <string.h>
27    
# Line 80  Line 81 
81    }    }
82  }  }
83    
84  static enum Class ** classes = NULL;  static const char * g_id;
85  static jschar ** lines = NULL;  static const jschar * g_characters;
86    static size_t g_num_characters;
87  static uint16_t num_characters_in_line(jschar * line) {  static Stream * g_output;
88    uint16_t result = 0;  static size_t character_offset;
89    while (line[result] != '\0') {  static uint16_t line_num;
90      result++;  static uint16_t column_num;
91    static enum Class current_class;
92    
93    static void output_character(jschar c, enum Class class) {
94      if (class != current_class) {
95        /* output the end tag */
96        if (current_class != CLASS_NONE) {
97          Stream_write_string(g_output, "</span>");
98        }
99    
100        current_class = class;
101    
102        /* output the start tag */
103        if (current_class != CLASS_NONE) {
104          Stream_printf(g_output, "<span class=\"%s\">", get_class_name(class));
105        }
106    }    }
   return result;  
 }  
107    
108  static void mark_token_chars(enum Class class, uint16_t start_line, uint16_t start_column, uint16_t end_line, uint16_t end_column) {    switch (c) {
109    for (uint16_t i = start_line; i <= end_line; i++) {    case '&':
110      uint16_t c1 = i == start_line? start_column: 0;      Stream_write_string(g_output, "&amp;");
111      uint16_t c2 = i == end_line? end_column: num_characters_in_line(lines[i - 1]);      break;
112      for (uint16_t j = c1; j < c2; j++) {    case '<':
113        classes[i - 1][j] = class;      Stream_write_string(g_output, "&lt;");
114        break;
115      case '>':
116        Stream_write_string(g_output, "&gt;");
117        break;
118      case '\n':
119        Stream_write_char(g_output, c);
120        break;
121      default:
122        if (c == '\t' || (32 <= c && c <= 126)) {
123          Stream_write_char(g_output, c);
124        }
125        else {
126          Stream_printf(g_output, "&#%d;", c);
127      }      }
128        break;
129    }    }
130  }  }
131    
132  static void mark_nontoken_chars(uint16_t start_line, uint16_t start_column, uint16_t end_line, uint16_t end_column) {  static void mark_nontoken_chars(uint16_t end_line, uint16_t end_column) {
133    enum State {    enum State {
134      STATE_NORMAL,      STATE_NORMAL,
135      STATE_LINE_COMMENT,      STATE_LINE_COMMENT,
# Line 109  Line 137 
137    };    };
138    
139    enum State state = STATE_NORMAL;    enum State state = STATE_NORMAL;
140    for (uint16_t i = start_line; i <= end_line; i++) {    while (character_offset < g_num_characters) {
141      uint16_t c1 = i == start_line? start_column: 0;      if (end_line != 0 && line_num > end_line) {
142      uint16_t c2 = i == end_line? end_column: num_characters_in_line(lines[i - 1]);        break;
     for (uint16_t j = c1; j < c2; j++) {  
       jschar c = lines[i - 1][j];  
       switch (state) {  
       case STATE_NORMAL:  
         if (c == '/' && j + 1 < c2 && lines[i - 1][j + 1] == '/') {  
           state = STATE_LINE_COMMENT;  
           classes[i - 1][j] = CLASS_COMMENT;  
         }  
         else if (c == '/' && j + 1 < c2 && lines[i - 1][j + 1] == '*') {  
           state = STATE_MULTILINE_COMMENT;  
           classes[i - 1][j] = CLASS_COMMENT;  
           j++;  
           classes[i - 1][j] = CLASS_COMMENT;  
         }  
         else {  
           classes[i - 1][j] = CLASS_NONE;  
         }  
         break;  
       case STATE_LINE_COMMENT:  
         if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {  
           state = STATE_NORMAL;  
           classes[i - 1][j] = CLASS_NONE;  
         }  
         else {  
           classes[i - 1][j] = CLASS_COMMENT;  
         }  
         break;  
       case STATE_MULTILINE_COMMENT:  
         classes[i - 1][j] = CLASS_COMMENT;  
         if (c == '*' && j + 1 < c2 && lines[i - 1][j + 1] == '/') {  
           j++;  
           classes[i - 1][j] = CLASS_COMMENT;  
           state = STATE_NORMAL;  
         }  
         break;  
       }  
143      }      }
144      /* end of the line */      else if (line_num == end_line && column_num >= end_column) {
145      if (state == STATE_LINE_COMMENT) {        break;
       state = STATE_NORMAL;  
146      }      }
   }  
 }  
147    
148  void jscoverage_highlight_js(JSContext * context, const char * id, const jschar * characters, size_t num_characters, Stream * output) {      jschar c = g_characters[character_offset];
149    /* count the lines - see GetChar in jsscan.c */      if (c == '\0') {
150    size_t i = 0;        fatal("%s: script contains NULL character", g_id);
151    uint16_t num_lines = 0;      }
152    while (i < num_characters) {  
153      if (num_lines == UINT16_MAX) {      switch (state) {
154        fatal("%s: script has more than 65535 lines", id);      case STATE_NORMAL:
155      }        if (c == '/' && character_offset + 1 < g_num_characters && g_characters[character_offset + 1] == '/') {
156      num_lines++;          state = STATE_LINE_COMMENT;
     jschar c;  
     while (i < num_characters) {  
       c = characters[i];  
       if (c == '\0') {  
         fatal("%s: script contains NULL character", id);  
157        }        }
158          else if (c == '/' && character_offset + 1 < g_num_characters && g_characters[character_offset + 1] == '*') {
159            state = STATE_MULTILINE_COMMENT;
160            output_character('/', CLASS_COMMENT);
161            output_character('*', CLASS_COMMENT);
162            character_offset += 2;
163            if (column_num >= UINT16_MAX - 1) {
164              fatal("%s: script contains line with more than 65,535 characters", g_id);
165            }
166            column_num += 2;
167            continue;
168          }
169          break;
170        case STATE_LINE_COMMENT:
171        if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {        if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {
172          break;          state = STATE_NORMAL;
173        }        }
174        i++;        break;
175      }      case STATE_MULTILINE_COMMENT:
176      if (i < num_characters) {        if (c == '*' && character_offset + 1 < g_num_characters && g_characters[character_offset + 1] == '/') {
177        i++;          output_character('*', CLASS_COMMENT);
178        if (c == '\r' && i < num_characters && characters[i] == '\n') {          output_character('/', CLASS_COMMENT);
179          i++;          state = STATE_NORMAL;
180            character_offset += 2;
181            if (column_num >= UINT16_MAX - 1) {
182              fatal("%s: script contains line with more than 65,535 characters", g_id);
183            }
184            column_num += 2;
185            continue;
186        }        }
187          break;
188      }      }
   }  
   
   lines = xnew(jschar *, num_lines);  
   classes = xnew(enum Class *, num_lines);  
189    
190    uint16_t line_num = 0;      character_offset++;
191    i = 0;      if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {
192    while (i < num_characters) {        if (line_num == UINT16_MAX) {
193      size_t line_start = i;          fatal("%s: script contains more than 65,535 lines", g_id);
194      jschar c;        }
195      while (i < num_characters) {        line_num++;
196        c = characters[i];        column_num = 0;
197        if (c == '\r' || c == '\n' || c == 0x2028 || c == 0x2029) {        if (c == '\r' && character_offset < g_num_characters && g_characters[character_offset] == '\n') {
198          break;          character_offset++;
199        }        }
200        i++;        output_character('\n', CLASS_NONE);
201      }      }
202      size_t line_end = i;      else {
203      if (i < num_characters) {        if (column_num == UINT16_MAX) {
204        i++;          fatal("%s: script contains line with more than 65,535 characters", g_id);
205        if (c == '\r' && i < num_characters && characters[i] == '\n') {        }
206          i++;        column_num++;
207          if (state == STATE_NORMAL) {
208            output_character(c, CLASS_NONE);
209          }
210          else {
211            output_character(c, CLASS_COMMENT);
212        }        }
213      }      }
     size_t line_length = line_end - line_start;  
     if (line_length >= UINT16_MAX) {  
       fatal("%s: script has line with 65535 characters or more", id);  
     }  
     jschar * line = xnew(jschar, line_length + 1);  
     memcpy(line, characters + line_start, sizeof(jschar) * line_length);  
     line[line_length] = '\0';  
     lines[line_num] = line;  
     classes[line_num] = xnew(enum Class, line_length);  
     line_num++;  
214    }    }
215    }
216    
217    void jscoverage_highlight_js(JSContext * context, const char * id, const jschar * characters, size_t num_characters, Stream * output) {
218      g_id = id;
219      g_characters = characters;
220      g_num_characters = num_characters;
221      g_output = output;
222    
223      character_offset = 0;
224      line_num = 1;
225      column_num = 0;
226      current_class = CLASS_NONE;
227    
228    /* tokenize the JavaScript */    /* tokenize the JavaScript */
229    JSTokenStream * token_stream = js_NewTokenStream(context, characters, num_characters, NULL, 1, NULL);    JSTokenStream * token_stream = js_NewTokenStream(context, characters, num_characters, NULL, 1, NULL);
# Line 258  Line 265 
265       */       */
266      JS_KEEP_ATOMS(cx->runtime);      JS_KEEP_ATOMS(cx->runtime);
267    
   line_num = 1;  
   uint16_t column_num = 0;  
268    for (;;) {    for (;;) {
269      JSTokenType tt = js_GetToken(context, token_stream);      JSTokenType tt = js_GetToken(context, token_stream);
270    
# Line 268  Line 273 
273      }      }
274    
275      if (tt == TOK_EOF) {      if (tt == TOK_EOF) {
276        /* it seems t.pos is invalid for TOK_EOF??? */        mark_nontoken_chars(0, 0);
       /* mark the remaining chars */  
       if (num_lines == 0) {  
         break;  
       }  
       uint16_t end_line = num_lines;  
       uint16_t end_column = num_characters_in_line(lines[num_lines - 1]);  
       mark_nontoken_chars(line_num, column_num, end_line, end_column);  
277        break;        break;
278      }      }
279    
280      /* mark the chars before the token */      /* mark the chars before the token */
281      JSToken t = CURRENT_TOKEN(token_stream);      JSToken t = CURRENT_TOKEN(token_stream);
282      mark_nontoken_chars(line_num, column_num, t.pos.begin.lineno, t.pos.begin.index);      mark_nontoken_chars(t.pos.begin.lineno, t.pos.begin.index);
283    
284      /* mark the token */      /* mark the token */
285      enum Class class;      enum Class class;
# Line 460  Line 458 
458        abort();        abort();
459        break;        break;
460      }      }
     mark_token_chars(class, t.pos.begin.lineno, t.pos.begin.index, t.pos.end.lineno, t.pos.end.index);  
     if (tt == TOK_STRING) {  
       for (uint16_t i = t.pos.begin.index + 1; i < t.pos.end.index - 1; i++) {  
         jschar c = lines[t.pos.begin.lineno - 1][i];  
         if (c == '\\') {  
           mark_token_chars(CLASS_SPECIALCHAR, t.pos.begin.lineno, i, t.pos.begin.lineno, i + 2);  
           i++;  
         }  
       }  
     }  
461    
462      line_num = t.pos.end.lineno;      assert(t.pos.begin.lineno == t.pos.end.lineno);
463      column_num = t.pos.end.index;      if (t.pos.begin.index > t.pos.end.index) {
464    }        fatal("%s: script contains line with more than 65,535 characters", id);
465        }
466    /* output the highlighted code */      for (uint16_t i = t.pos.begin.index; i < t.pos.end.index; i++) {
467    enum Class class = CLASS_NONE;        assert(character_offset < num_characters);
468    for (uint16_t i = 0; i < num_lines; i++) {        jschar c = characters[character_offset];
469      uint16_t length = num_characters_in_line(lines[i]);        if (tt == TOK_STRING && c == '\\') {
470      for (uint16_t j = 0; j < length; j++) {          output_character(c, CLASS_SPECIALCHAR);
471        jschar c = lines[i][j];          character_offset++;
472        if (classes[i][j] != class) {          i++;
473          if (class != CLASS_NONE) {          assert(character_offset < num_characters);
474            Stream_write_string(output, "</span>");          c = characters[character_offset];
475          }          output_character(c, CLASS_SPECIALCHAR);
476          class = classes[i][j];          character_offset++;
         if (class != CLASS_NONE) {  
           Stream_printf(output, "<span class=\"%s\">", get_class_name(class));  
         }  
       }  
       if (c == '&') {  
         Stream_write_string(output, "&amp;");  
       }  
       else if (c == '<') {  
         Stream_write_string(output, "&lt;");  
       }  
       else if (c == '>') {  
         Stream_write_string(output, "&gt;");  
       }  
       else if (c == '\t' || (32 <= c && c <= 126)) {  
         Stream_write_char(output, c);  
477        }        }
478        else {        else {
479          Stream_printf(output, "&#%d;", c);          output_character(c, class);
480            character_offset++;
481        }        }
482      }      }
483      if (class != CLASS_NONE) {  
484        Stream_write_string(output, "</span>");      line_num = t.pos.end.lineno;
485        class = CLASS_NONE;      column_num = t.pos.end.index;
     }  
     Stream_write_char(output, '\n');  
486    }    }
487    
488    for (uint16_t i = 0; i < num_lines; i++) {    if (current_class != CLASS_NONE) {
489      free(lines[i]);      output_character('\n', CLASS_NONE);
     free(classes[i]);  
490    }    }
   free(lines);  
   free(classes);  
491    
492    /* cleanup */    /* cleanup */
493    JS_UNKEEP_ATOMS(cx->runtime);    JS_UNKEEP_ATOMS(cx->runtime);

Legend:
Removed from v.179  
changed lines
  Added in v.213

  ViewVC Help
Powered by ViewVC 1.1.24