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