Blender  V2.93
text_format_osl.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software Foundation,
13  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14  */
15 
20 #include <string.h>
21 
22 #include "BLI_blenlib.h"
23 
24 #include "DNA_space_types.h"
25 #include "DNA_text_types.h"
26 
27 #include "BKE_text.h"
28 
29 #include "text_format.h"
30 
31 /* *** Local Functions (for format_line) *** */
32 
33 static int txtfmt_osl_find_builtinfunc(const char *string)
34 {
35  int i, len;
36 
37  /* Keep aligned args for readability. */
38  /* clang-format off */
39 
40  /* list is from
41  * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
42  */
43  if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
44  } else if (STR_LITERAL_STARTSWITH(string, "closure", len)) { i = len;
45  } else if (STR_LITERAL_STARTSWITH(string, "color", len)) { i = len;
46  } else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
47  } else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len;
48  } else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len;
49  } else if (STR_LITERAL_STARTSWITH(string, "emit", len)) { i = len;
50  } else if (STR_LITERAL_STARTSWITH(string, "float", len)) { i = len;
51  } else if (STR_LITERAL_STARTSWITH(string, "for", len)) { i = len;
52  } else if (STR_LITERAL_STARTSWITH(string, "if", len)) { i = len;
53  } else if (STR_LITERAL_STARTSWITH(string, "illuminance", len)) { i = len;
54  } else if (STR_LITERAL_STARTSWITH(string, "illuminate", len)) { i = len;
55  } else if (STR_LITERAL_STARTSWITH(string, "int", len)) { i = len;
56  } else if (STR_LITERAL_STARTSWITH(string, "matrix", len)) { i = len;
57  } else if (STR_LITERAL_STARTSWITH(string, "normal", len)) { i = len;
58  } else if (STR_LITERAL_STARTSWITH(string, "output", len)) { i = len;
59  } else if (STR_LITERAL_STARTSWITH(string, "point", len)) { i = len;
60  } else if (STR_LITERAL_STARTSWITH(string, "public", len)) { i = len;
61  } else if (STR_LITERAL_STARTSWITH(string, "return", len)) { i = len;
62  } else if (STR_LITERAL_STARTSWITH(string, "string", len)) { i = len;
63  } else if (STR_LITERAL_STARTSWITH(string, "struct", len)) { i = len;
64  } else if (STR_LITERAL_STARTSWITH(string, "vector", len)) { i = len;
65  } else if (STR_LITERAL_STARTSWITH(string, "void", len)) { i = len;
66  } else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
67  } else { i = 0;
68  }
69 
70  /* clang-format on */
71 
72  /* If next source char is an identifier (eg. 'i' in "definite") no match */
73  if (i == 0 || text_check_identifier(string[i])) {
74  return -1;
75  }
76  return i;
77 }
78 
79 static int txtfmt_osl_find_reserved(const char *string)
80 {
81  int i, len;
82 
83  /* Keep aligned args for readability. */
84  /* clang-format off */
85 
86  /* list is from...
87  * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
88  */
89  if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len;
90  } else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
91  } else if (STR_LITERAL_STARTSWITH(string, "catch", len)) { i = len;
92  } else if (STR_LITERAL_STARTSWITH(string, "char", len)) { i = len;
93  } else if (STR_LITERAL_STARTSWITH(string, "const", len)) { i = len;
94  } else if (STR_LITERAL_STARTSWITH(string, "delete", len)) { i = len;
95  } else if (STR_LITERAL_STARTSWITH(string, "default", len)) { i = len;
96  } else if (STR_LITERAL_STARTSWITH(string, "double", len)) { i = len;
97  } else if (STR_LITERAL_STARTSWITH(string, "enum", len)) { i = len;
98  } else if (STR_LITERAL_STARTSWITH(string, "extern", len)) { i = len;
99  } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
100  } else if (STR_LITERAL_STARTSWITH(string, "friend", len)) { i = len;
101  } else if (STR_LITERAL_STARTSWITH(string, "goto", len)) { i = len;
102  } else if (STR_LITERAL_STARTSWITH(string, "inline", len)) { i = len;
103  } else if (STR_LITERAL_STARTSWITH(string, "long", len)) { i = len;
104  } else if (STR_LITERAL_STARTSWITH(string, "new", len)) { i = len;
105  } else if (STR_LITERAL_STARTSWITH(string, "operator", len)) { i = len;
106  } else if (STR_LITERAL_STARTSWITH(string, "private", len)) { i = len;
107  } else if (STR_LITERAL_STARTSWITH(string, "protected", len)) { i = len;
108  } else if (STR_LITERAL_STARTSWITH(string, "short", len)) { i = len;
109  } else if (STR_LITERAL_STARTSWITH(string, "signed", len)) { i = len;
110  } else if (STR_LITERAL_STARTSWITH(string, "sizeof", len)) { i = len;
111  } else if (STR_LITERAL_STARTSWITH(string, "static", len)) { i = len;
112  } else if (STR_LITERAL_STARTSWITH(string, "switch", len)) { i = len;
113  } else if (STR_LITERAL_STARTSWITH(string, "template", len)) { i = len;
114  } else if (STR_LITERAL_STARTSWITH(string, "this", len)) { i = len;
115  } else if (STR_LITERAL_STARTSWITH(string, "throw", len)) { i = len;
116  } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
117  } else if (STR_LITERAL_STARTSWITH(string, "try", len)) { i = len;
118  } else if (STR_LITERAL_STARTSWITH(string, "typedef", len)) { i = len;
119  } else if (STR_LITERAL_STARTSWITH(string, "uniform", len)) { i = len;
120  } else if (STR_LITERAL_STARTSWITH(string, "union", len)) { i = len;
121  } else if (STR_LITERAL_STARTSWITH(string, "unsigned", len)) { i = len;
122  } else if (STR_LITERAL_STARTSWITH(string, "varying", len)) { i = len;
123  } else if (STR_LITERAL_STARTSWITH(string, "virtual", len)) { i = len;
124  } else if (STR_LITERAL_STARTSWITH(string, "volatile", len)) { i = len;
125  } else { i = 0;
126  }
127 
128  /* clang-format on */
129 
130  /* If next source char is an identifier (eg. 'i' in "definite") no match */
131  if (i == 0 || text_check_identifier(string[i])) {
132  return -1;
133  }
134  return i;
135 }
136 
137 /* Checks the specified source string for a OSL special name. This name must
138  * start at the beginning of the source string and must be followed by a non-
139  * identifier (see text_check_identifier(char)) or null character.
140  *
141  * If a special name is found, the length of the matching name is returned.
142  * Otherwise, -1 is returned. */
143 
144 static int txtfmt_osl_find_specialvar(const char *string)
145 {
146  int i, len;
147 
148  /* Keep aligned args for readability. */
149  /* clang-format off */
150 
151  /* OSL shader types */
152  if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len;
153  } else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len;
154  } else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len;
155  } else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len;
156  } else { i = 0;
157  }
158 
159  /* clang-format on */
160 
161  /* If next source char is an identifier (eg. 'i' in "definite") no match */
162  if (i == 0 || text_check_identifier(string[i])) {
163  return -1;
164  }
165  return i;
166 }
167 
168 /* matches py 'txtfmt_osl_find_decorator' */
169 static int txtfmt_osl_find_preprocessor(const char *string)
170 {
171  if (string[0] == '#') {
172  int i = 1;
173  /* Whitespace is ok '# foo' */
174  while (text_check_whitespace(string[i])) {
175  i++;
176  }
177  while (text_check_identifier(string[i])) {
178  i++;
179  }
180  return i;
181  }
182  return -1;
183 }
184 
185 static char txtfmt_osl_format_identifier(const char *str)
186 {
187  char fmt;
188 
189  /* Keep aligned args for readability. */
190  /* clang-format off */
191 
192  if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
193  } else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
194  } else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED;
195  } else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE;
196  } else { fmt = FMT_TYPE_DEFAULT;
197  }
198 
199  /* clang-format on */
200 
201  return fmt;
202 }
203 
204 static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_next)
205 {
206  FlattenString fs;
207  const char *str;
208  char *fmt;
209  char cont_orig, cont, find, prev = ' ';
210  int len, i;
211 
212  /* Get continuation from previous line */
213  if (line->prev && line->prev->format != NULL) {
214  fmt = line->prev->format;
215  cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
216  BLI_assert((FMT_CONT_ALL & cont) == cont);
217  }
218  else {
219  cont = FMT_CONT_NOP;
220  }
221 
222  /* Get original continuation from this line */
223  if (line->format != NULL) {
224  fmt = line->format;
225  cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
226  BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
227  }
228  else {
229  cont_orig = 0xFF;
230  }
231 
232  len = flatten_string(st, &fs, line->line);
233  str = fs.buf;
234  if (!text_check_format_len(line, len)) {
235  flatten_string_free(&fs);
236  return;
237  }
238  fmt = line->format;
239 
240  while (*str) {
241  /* Handle escape sequences by skipping both \ and next char */
242  if (*str == '\\') {
243  *fmt = prev;
244  fmt++;
245  str++;
246  if (*str == '\0') {
247  break;
248  }
249  *fmt = prev;
250  fmt++;
252  continue;
253  }
254  /* Handle continuations */
255  if (cont) {
256  /* C-Style comments */
257  if (cont & FMT_CONT_COMMENT_C) {
258  if (*str == '*' && *(str + 1) == '/') {
259  *fmt = FMT_TYPE_COMMENT;
260  fmt++;
261  str++;
262  *fmt = FMT_TYPE_COMMENT;
263  cont = FMT_CONT_NOP;
264  }
265  else {
266  *fmt = FMT_TYPE_COMMENT;
267  }
268  /* Handle other comments */
269  }
270  else {
271  find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
272  if (*str == find) {
273  cont = 0;
274  }
275  *fmt = FMT_TYPE_STRING;
276  }
277 
279  }
280  /* Not in a string... */
281  else {
282  /* Deal with comments first */
283  if (*str == '/' && *(str + 1) == '/') {
284  /* fill the remaining line */
285  text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format));
286  }
287  /* C-Style (multi-line) comments */
288  else if (*str == '/' && *(str + 1) == '*') {
289  cont = FMT_CONT_COMMENT_C;
290  *fmt = FMT_TYPE_COMMENT;
291  fmt++;
292  str++;
293  *fmt = FMT_TYPE_COMMENT;
294  }
295  else if (ELEM(*str, '"', '\'')) {
296  /* Strings */
297  find = *str;
298  cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
299  *fmt = FMT_TYPE_STRING;
300  }
301  /* Whitespace (all ws. has been converted to spaces) */
302  else if (*str == ' ') {
303  *fmt = FMT_TYPE_WHITESPACE;
304  }
305  /* Numbers (digits not part of an identifier and periods followed by digits) */
306  else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
307  (*str == '.' && text_check_digit(*(str + 1)))) {
308  *fmt = FMT_TYPE_NUMERAL;
309  }
310  /* Punctuation */
311  else if ((*str != '#') && text_check_delim(*str)) {
312  *fmt = FMT_TYPE_SYMBOL;
313  }
314  /* Identifiers and other text (no previous ws. or delims. so text continues) */
315  else if (prev == FMT_TYPE_DEFAULT) {
317  *fmt = FMT_TYPE_DEFAULT;
318  }
319  /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
320  else {
321  /* Keep aligned args for readability. */
322  /* clang-format off */
323 
324  /* Special vars(v) or built-in keywords(b) */
325  /* keep in sync with 'txtfmt_osl_format_identifier()' */
326  if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
327  } else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
328  } else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
329  } else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
330  }
331 
332  /* clang-format on */
333 
334  if (i > 0) {
335  if (prev == FMT_TYPE_DIRECTIVE) { /* can contain utf8 */
336  text_format_fill(&str, &fmt, prev, i);
337  }
338  else {
339  text_format_fill_ascii(&str, &fmt, prev, i);
340  }
341  }
342  else {
344  *fmt = FMT_TYPE_DEFAULT;
345  }
346  }
347  }
348  prev = *fmt;
349  fmt++;
350  str++;
351  }
352 
353  /* Terminate and add continuation char */
354  *fmt = '\0';
355  fmt++;
356  *fmt = cont;
357 
358  /* If continuation has changed and we're allowed, process the next line */
359  if (cont != cont_orig && do_next && line->next) {
360  txtfmt_osl_format_line(st, line->next, do_next);
361  }
362 
363  flatten_string_free(&fs);
364 }
365 
367 {
368  static TextFormatType tft = {NULL};
369  static const char *ext[] = {"osl", NULL};
370 
373  tft.ext = ext;
374 
376 }
bool text_check_identifier(const char ch)
Definition: text.c:2426
bool text_check_digit(const char ch)
Definition: text.c:2415
bool text_check_delim(const char ch)
Definition: text.c:2402
bool text_check_whitespace(const char ch)
Definition: text.c:2481
#define BLI_assert(a)
Definition: BLI_assert.h:58
int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL()
Definition: string_utf8.c:508
#define ELEM(...)
#define str(s)
void(* format_line)(SpaceText *st, TextLine *line, const bool do_next)
Definition: text_format.h:72
char(* format_identifier)(const char *string)
Definition: text_format.h:61
const char ** ext
Definition: text_format.h:74
char * format
char * line
struct TextLine * prev
struct TextLine * next
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
Definition: text_format.c:71
void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
Definition: text_format.c:151
void flatten_string_free(FlattenString *fs)
Definition: text_format.c:104
void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
Definition: text_format.c:177
void ED_text_format_register(TextFormatType *tft)
Definition: text_format.c:195
int text_check_format_len(TextLine *line, uint len)
Definition: text_format.c:124
#define STR_LITERAL_STARTSWITH(str, str_literal, len_var)
Definition: text_format.h:110
@ FMT_TYPE_DIRECTIVE
Definition: text_format.h:89
@ FMT_TYPE_STRING
Definition: text_format.h:87
@ FMT_TYPE_COMMENT
Definition: text_format.h:81
@ FMT_TYPE_SPECIAL
Definition: text_format.h:91
@ FMT_TYPE_DEFAULT
Definition: text_format.h:97
@ FMT_TYPE_KEYWORD
Definition: text_format.h:95
@ FMT_TYPE_WHITESPACE
Definition: text_format.h:79
@ FMT_TYPE_NUMERAL
Definition: text_format.h:85
@ FMT_TYPE_RESERVED
Definition: text_format.h:93
@ FMT_TYPE_SYMBOL
Definition: text_format.h:83
@ FMT_CONT_QUOTEDOUBLE
Definition: text_format.h:40
@ FMT_CONT_QUOTESINGLE
Definition: text_format.h:39
@ FMT_CONT_NOP
Definition: text_format.h:38
@ FMT_CONT_COMMENT_C
Definition: text_format.h:44
#define FMT_CONT_ALL
Definition: text_format.h:46
static char txtfmt_osl_format_identifier(const char *str)
static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_next)
void ED_text_format_register_osl(void)
static int txtfmt_osl_find_builtinfunc(const char *string)
static int txtfmt_osl_find_preprocessor(const char *string)
static int txtfmt_osl_find_specialvar(const char *string)
static int txtfmt_osl_find_reserved(const char *string)
uint len