fix own regression in 2.66 [#34610] Text editor: Syntax highlighting freezes
[blender.git] / source / blender / editors / space_text / text_format.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  *
17  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
18  * All rights reserved.
19  *
20  * The Original Code is: all of this file.
21  *
22  * Contributor(s): none yet.
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_text/text_format.c
28  *  \ingroup sptext
29  */
30
31 #include <string.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_blenlib.h"
36
37 #include "DNA_text_types.h"
38 #include "DNA_space_types.h"
39
40 #include "text_format.h"
41
42
43 /****************** flatten string **********************/
44
45 static void flatten_string_append(FlattenString *fs, const char *c, int accum, int len)
46 {
47         int i;
48
49         if (fs->pos + len > fs->len) {
50                 char *nbuf; int *naccum;
51                 fs->len *= 2;
52
53                 nbuf = MEM_callocN(sizeof(*fs->buf) * fs->len, "fs->buf");
54                 naccum = MEM_callocN(sizeof(*fs->accum) * fs->len, "fs->accum");
55
56                 memcpy(nbuf, fs->buf, fs->pos * sizeof(*fs->buf));
57                 memcpy(naccum, fs->accum, fs->pos * sizeof(*fs->accum));
58
59                 if (fs->buf != fs->fixedbuf) {
60                         MEM_freeN(fs->buf);
61                         MEM_freeN(fs->accum);
62                 }
63
64                 fs->buf = nbuf;
65                 fs->accum = naccum;
66         }
67
68         for (i = 0; i < len; i++) {
69                 fs->buf[fs->pos + i] = c[i];
70                 fs->accum[fs->pos + i] = accum;
71         }
72
73         fs->pos += len;
74 }
75
76 int flatten_string(SpaceText *st, FlattenString *fs, const char *in)
77 {
78         int r, i, total = 0;
79
80         memset(fs, 0, sizeof(FlattenString));
81         fs->buf = fs->fixedbuf;
82         fs->accum = fs->fixedaccum;
83         fs->len = sizeof(fs->fixedbuf);
84
85         for (r = 0, i = 0; *in; r++) {
86                 if (*in == '\t') {
87                         i = st->tabnumber - (total % st->tabnumber);
88                         total += i;
89
90                         while (i--)
91                                 flatten_string_append(fs, " ", r, 1);
92
93                         in++;
94                 }
95                 else {
96                         size_t len = BLI_str_utf8_size_safe(in);
97                         flatten_string_append(fs, in, r, len);
98                         in += len;
99                         total++;
100                 }
101         }
102
103         flatten_string_append(fs, "\0", r, 1);
104
105         return total;
106 }
107
108 void flatten_string_free(FlattenString *fs)
109 {
110         if (fs->buf != fs->fixedbuf)
111                 MEM_freeN(fs->buf);
112         if (fs->accum != fs->fixedaccum)
113                 MEM_freeN(fs->accum);
114 }
115
116 /* takes a string within fs->buf and returns its length */
117 int flatten_string_strlen(FlattenString *fs, const char *str)
118 {
119         const int len = (fs->pos - (int)(str - fs->buf)) - 1;
120         BLI_assert(strlen(str) == len);
121         return len;
122 }
123
124 /* Ensures the format string for the given line is long enough, reallocating
125  * as needed. Allocation is done here, alone, to ensure consistency. */
126 int text_check_format_len(TextLine *line, unsigned int len)
127 {
128         if (line->format) {
129                 if (strlen(line->format) < len) {
130                         MEM_freeN(line->format);
131                         line->format = MEM_mallocN(len + 2, "SyntaxFormat");
132                         if (!line->format) return 0;
133                 }
134         }
135         else {
136                 line->format = MEM_mallocN(len + 2, "SyntaxFormat");
137                 if (!line->format) return 0;
138         }
139
140         return 1;
141 }
142
143 /**
144  * Fill the string with formatting constant,
145  * advancing \a str_p and \a fmt_p
146  *
147  * \param len length in bytes of \a fmt_p to fill.
148  */
149 void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len)
150 {
151         const char *str = *str_p;
152         char *fmt = *fmt_p;
153         int i = 0;
154
155         while (i < len) {
156                 const int size = BLI_str_utf8_size_safe(str);
157                 *fmt++ = type;
158
159                 str += size;
160                 i   += 1;
161         }
162
163         str--;
164         fmt--;
165
166         BLI_assert(*str != '\0');
167
168         *str_p = str;
169         *fmt_p = fmt;
170 }
171 /**
172  * ascii version of #text_format_fill,
173  * use when we no the text being stepped over is ascii (as is the case for most keywords)
174  */
175 void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len)
176 {
177         const char *str = *str_p;
178         char *fmt = *fmt_p;
179
180         memset(fmt, type, len);
181
182         str += len - 1;
183         fmt += len - 1;
184
185         BLI_assert(*str != '\0');
186
187         *str_p = str;
188         *fmt_p = fmt;
189 }
190
191 /* *** Registration *** */
192 static ListBase tft_lb = {NULL, NULL};
193 void ED_text_format_register(TextFormatType *tft)
194 {
195         BLI_addtail(&tft_lb, tft);
196 }
197
198 TextFormatType *ED_text_format_get(Text *text)
199 {
200         TextFormatType *tft;
201
202         if (text) {
203                 const char *text_ext = strchr(text->id.name + 2, '.');
204                 if (text_ext) {
205                         text_ext++;  /* skip the '.' */
206                         /* Check all text formats in the static list */
207                         for (tft = tft_lb.first; tft; tft = tft->next) {
208                                 /* All formats should have an ext, but just in case */
209                                 const char **ext;
210                                 for (ext = tft->ext; *ext; ext++) {
211                                         /* If extension matches text name, return the matching tft */
212                                         if (BLI_strcasecmp(text_ext, *ext) == 0) {
213                                                 return tft;
214                                         }
215                                 }
216                         }
217                 }
218
219                 /* If we make it here we never found an extension that worked - return 
220                  * the "default" text format */
221                 return tft_lb.first;
222         }
223         else {
224                 /* Return the "default" text format */
225                 return tft_lb.first;
226         }
227 }