1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Thu Feb 12 14:50:38 2009
19 ****************************************************************************/
20
21 #include <stdlib.h>
22
23 #include "tkgate.h"
24
25 static GModuleDef *hdl_active_module = 0;
26
27 int hdl_isactive;
28
29 /*****************************************************************************
30 *
31 * Data structure for holding information about a module definition from the
32 * HDL text buffer. This data structure is used only in this file and only
33 * as a return value from hdl_findPartitions().
34 *
35 *****************************************************************************/
36 typedef struct {
37 char *comment_start; // Start of comments for module.
38 char *module_line; // Pointer to beginning of line with "module" in it.
39 char *name; // Pointer to beginning of module name
40 int name_len; // Number of characters in module name.
41 int module_length; // Total length of module
42 char *endmodule_line; // Pointer to beginning of line with "endmodule" in it.
43 char *module_end; // End of module definition
44 } HdlModuleData;
45
46
47 /*****************************************************************************
48 *
49 * Check to make sure that s1 matches the first n characters of s2.
50 *
51 *****************************************************************************/
ismatch(const char * s1,const char * s2,int n)52 static int ismatch(const char *s1,const char *s2,int n)
53 {
54
55 if (strlen(s1) != n) return 0;
56 return strncmp(s1,s2,n) == 0;
57 }
58
59 /*****************************************************************************
60 *
61 * Load HDL text from module definition to editor.
62 *
63 * Parameters:
64 * M Module to be loaded into hdl editor.
65 *
66 *****************************************************************************/
hdl_load(GModuleDef * M)67 void hdl_load(GModuleDef *M)
68 {
69 hdl_active_module = M;
70
71 if (M->m_text) {
72 DoTcl("HdlEditor::enable");
73 DoTcl("HdlEditor::clear");
74
75 DoTclL("HdlEditor::loadText",M->m_text,NULL);
76
77 if (GModuleDef_isDataProtected(M))
78 DoTcl("HdlEditor::disable");
79 } else {
80 printf("hdl_load ignored for non-HDL module [%s]\n",M->m_name);
81 }
82
83 }
84
85 /*****************************************************************************
86 *
87 * Save HDL text in editor to module definition.
88 *
89 * Parameters:
90 * name Expected name of module to save to or null for current module.
91 *****************************************************************************/
hdl_save(const char * name)92 int hdl_save(const char *name)
93 {
94 GModuleDef *M;
95 int rvalue = 0;
96 const char *text;
97
98 if (name)
99 M = env_findModule(name);
100 else
101 M = hdl_active_module;
102
103 if (!M) {
104 /* We must have tried to close the HDL editor while not editing an HDL module */
105 return rvalue;
106 }
107 if (M->m_type != MT_TEXTHDL) return 0;
108
109 DoTcl("HdlEditor::dumpText");
110 text = Tcl_GetStringResult(TkGate.tcl);
111
112 #if 0
113 printf("hdl_save(%s)\n",M->m_name);
114 #endif
115
116 if (strcmp(text, M->m_text) == 0) return 0;
117
118 /*
119 * Move text from the text widget into tcl variables
120 */
121 ob_touch(M);
122 GModuleDef_saveText(M,text);
123 M->m_needScan = 1;
124
125 return rvalue;
126 }
127
128 /*****************************************************************************
129 *
130 * Find the points in a text block at which modules are defined.
131 *
132 * Parameters:
133 * text Text block to partition
134 * module_data[] Array of lines containing 'module' or 'primitive'
135 * n Number of element in module data array.
136 *
137 *****************************************************************************/
hdl_findPartitions(char * text,HdlModuleData * module_data,int n)138 static int hdl_findPartitions(char *text,HdlModuleData *module_data,int n)
139 {
140 char *token_begin,*token_end;
141 char *p = text;
142 int r;
143 int state = 0; /* 0 = outside module, 1 = inside module */
144 int count = 0;
145
146
147 module_data[0].comment_start = text;
148
149 while ((r = getNextToken(&p, &token_begin, &token_end)) != ST_END) {
150 int len = token_end-token_begin;
151
152 if (r != ST_LITERAL) continue;
153
154 if (ismatch("module",token_begin,len) || ismatch("primitive",token_begin,len)) {
155 if (state == 1) {
156 /* got a module begin while still in a module */
157 } else {
158 module_data[count].module_line = getLineStart(token_begin,text);
159
160 if (getNextToken(&p, &token_begin, &token_end) == ST_END) break;
161
162 module_data[count].name = token_begin;
163 module_data[count].name_len = token_end - token_begin;
164 state = 1;
165 }
166 } else if (ismatch("endmodule",token_begin,len) || ismatch("endprimitive",token_begin,len)) {
167 if (state == 0) {
168 /* got an endmodule while not in a module definition. */
169 } else {
170 state = 0;
171 module_data[count].endmodule_line = getLineStart(token_begin,text);
172 module_data[count].module_end = getLineEnd(token_end);
173 if (*module_data[count].module_end == '\n') module_data[count].module_end++;
174 module_data[count].module_length = module_data[count].module_end - module_data[count].comment_start;
175 if (++count < n) {
176 module_data[count].comment_start = module_data[count-1].module_end;
177 } else
178 return count;
179 }
180 }
181 }
182
183 /*
184 * No endmodule was found.
185 */
186 if (state) {
187 module_data[count].endmodule_line = p;
188 module_data[count].module_end = p;
189 module_data[count].module_length = module_data[count].module_end - module_data[count].comment_start;
190 count++;
191 }
192
193 /*
194 * Last module should snarf text to the end of the buffer.
195 */
196 if (count > 0) {
197 module_data[count-1].module_end = p;
198 module_data[count-1].module_length = module_data[count-1].module_end - module_data[count-1].comment_start;
199 }
200
201 return count;
202 }
203
204 /*****************************************************************************
205 *
206 * Replace the name of a module.
207 *
208 * Parameters:
209 * M Module to be renamed.
210 * new_name New module name.
211 *
212 * Returns: Non-zero on error.
213 *
214 *****************************************************************************/
hdl_replaceName(GModuleDef * M,const char * new_name)215 int hdl_replaceName(GModuleDef *M,const char *new_name)
216 {
217 int new_len = strlen(new_name);
218 char *src_text = M->m_text;
219 int src_len = strlen(src_text);
220 int name_len;
221 char *name_ptr;
222 char *name_end;
223 int name_offset;
224 HdlModuleData module_data[2];
225 int npart;
226 char *text;
227
228 npart = hdl_findPartitions(M->m_text,module_data,2);
229 if (npart != 1) return -1;
230
231 name_ptr = module_data[0].name;
232 name_len = module_data[0].name_len;
233 name_end = name_ptr + name_len;
234 name_offset = (name_ptr-src_text);
235
236 text = (char*) malloc(src_len+new_len-name_len+1);
237
238 memmove(text, src_text, name_offset);
239 memmove(text+name_offset, new_name, new_len);
240 strcpy(text+name_offset+new_len, name_end);
241
242 GModuleDef_saveText(M,text);
243 free(text);
244
245 return 0;
246 }
247
248
249
250
251 /*****************************************************************************
252 *
253 * Split HDL text in module M into multiple modules.
254 *
255 * Parameters:
256 * M Module that this text is a part of.
257 * module_data[] Array of module data descriptors
258 * module_count Number of modules.
259 *
260 *****************************************************************************/
hdl_splitModules(GModuleDef * M,HdlModuleData * module_data,int module_count)261 int hdl_splitModules(GModuleDef *M,HdlModuleData *module_data,int module_count)
262 {
263 int i,keep_idx = 0;
264
265 /*
266 * Find the module that we are going to keep as part of M's definiton, or use
267 * the first module if we can't find a matching name.
268 */
269 for (i = 0;i < module_count;i++) {
270 if (module_data[i].name_len > (STRMAX-10)) {
271 /* Found a very long module name. */
272 return -1;
273 }
274 if (ismatch(M->m_name, module_data[i].name, module_data[i].name_len)) {
275 keep_idx = i;
276 }
277 }
278
279 for (i = 0;i < module_count;i++) {
280 char modName[STRMAX],*p;
281 int count = 0;
282 int length = module_data[i].module_length;
283 GModuleDef *new_M;
284
285 if (i == keep_idx) continue;
286
287 /*
288 * Make sure the target name does not exist. If it does append a number
289 * to the end until we find an available module name.
290 */
291 strncpy(modName, module_data[i].name, module_data[i].name_len);
292 modName[module_data[i].name_len] = 0;
293 p = modName + strlen(modName);
294 while (env_findModule(modName)) {
295 sprintf(p,"_%d",count++);
296 }
297 new_M = env_defineModule(modName,0);
298 new_M->m_type = MT_TEXTHDL;
299 GModuleDef_allocText(new_M,length+1);
300 memmove(new_M->m_text, module_data[i].comment_start, length);
301 new_M->m_text[length] = 0;
302 if (count != 0)
303 hdl_replaceName(new_M,modName);
304 }
305
306 memmove(M->m_text, module_data[keep_idx].comment_start, module_data[keep_idx].module_length);
307 M->m_text[module_data[keep_idx].module_length] = 0;
308 if (!ismatch(M->m_name,module_data[keep_idx].name,module_data[keep_idx].name_len))
309 hdl_replaceName(M,M->m_name);
310
311 #if 0
312 printf("BEGIN KEEP\n%s\nEND KEEP\n",M->m_text);
313 #endif
314
315 return 0;
316 }
317
318 /*****************************************************************************
319 *
320 * Save HDL text in editor to module definition with consitency checks.
321 *
322 * Parameters:
323 * name Expected name of module to save to or null for current module.
324 *
325 * Save back hdl text to a module. The HDL text is scanned to make sure it
326 * is being saved with the correct module. The following actions are also
327 * taken as appropriate:
328 *
329 * 1) If the name of the module in the text definition does not match the
330 * current name of the module, rename the module.
331 *
332 * 2) If there is more than one module definition, split the text into
333 * multiple modules.
334 *
335 * 3) If there are is no module definition, add a simple empty definition.
336 *
337 * 4) If any module names in 1) or 2) are in use, manipulate the module names.
338 *
339 *****************************************************************************/
hdl_checkSave(const char * name)340 int hdl_checkSave(const char *name)
341 {
342 int module_count = 0;
343 HdlModuleData module_data[MAXMODS];
344 GModuleDef *M;
345 const char *text;
346 int rvalue = 0;
347
348 if (name)
349 M = env_findModule(name);
350 else
351 M = hdl_active_module;
352
353 if (!M) {
354 /* We must have tried to close the HDL editor while not editing an HDL module */
355 return rvalue;
356 }
357
358 if (M->m_type != MT_TEXTHDL) return 0;
359
360 ob_touch(M);
361 M->m_needScan = 1;
362
363 DoTcl("HdlEditor::dumpText");
364 text = Tcl_GetStringResult(TkGate.tcl);
365
366 /*
367 * Turn text into a copy. Use non-ob functions since we only use it here
368 */
369 text = strdup(text);
370
371 /*
372 * Find the partition points for modules
373 */
374 module_count = hdl_findPartitions((char *)text,module_data,MAXMODS);
375
376 ob_touch(M);
377
378 if (module_count == 0) {
379 /*
380 * If no modules where found, copy any available text and add a module/endmodule
381 * block with the appropriate name.
382 */
383 char buf[STRMAX];
384
385 sprintf(buf,"module %s;\n\nendmodule\n",M->m_name);
386 GModuleDef_saveText(M,buf);
387
388 module_data[0].comment_start = M->m_text;
389 module_data[0].module_line = M->m_text;
390 module_data[0].name = M->m_text + 7; /* Position of module name */
391 module_data[0].name_len = strlen(M->m_name);
392 module_data[0].endmodule_line = M->m_text + strlen(M->m_text);
393 module_data[0].module_end = module_data[0].endmodule_line;
394 module_count = 1;
395 DoTclL("HdlEditor::loadText",M->m_text,NULL);
396 } else if (module_count == 1) {
397 /*
398 * If a single module was found, store the HDL text back in the module. Rename the
399 * module if it was changed in the HDL text.
400 */
401
402 GModuleDef_saveText(M,text);
403
404 if (!ismatch(M->m_name,module_data[0].name,module_data[0].name_len)) {
405 DoTcl("HdlEditor::askRename");
406 if (strcmp(Tcl_GetStringResult(TkGate.tcl),"autoedit") == 0) {
407 hdl_replaceName(M,M->m_name);
408 DoTclL("HdlEditor::loadText",M->m_text,NULL);
409 } else if (strcmp(Tcl_GetStringResult(TkGate.tcl),"ignore") == 0) {
410 /* Do nothing */
411 } else { /* cancel */
412 rvalue = -1;
413 }
414 }
415 } else {
416 /*
417 * If there is more than one module in the text block, we can either split them into
418 * separate modules, or comment out everything after the first module. Ask the user
419 * which action they want to take.
420 */
421 DoTcl("HdlEditor::askSaveOption");
422 if (strcmp(Tcl_GetStringResult(TkGate.tcl),"split") == 0) {
423 GModuleDef_saveText(M, text);
424 hdl_splitModules(M,module_data,module_count);
425 DoTclL("HdlEditor::loadText",M->m_text,NULL);
426 } else if (strcmp(Tcl_GetStringResult(TkGate.tcl),"ignore") == 0) {
427 GModuleDef_saveText(M, text);
428 } else {
429 /* "cancel" or unknown value */
430 GModuleDef_saveText(M, text);
431 rvalue = -1;
432 }
433 }
434
435 if (text) free((void*)text);
436
437 return rvalue;
438 }
439
440 /*****************************************************************************
441 *
442 * Save the cursor position in the specified module.
443 *
444 * Parameters:
445 * name Name of module
446 * line Line number in buffer
447 * pos Character position on line.
448 *
449 *****************************************************************************/
hdl_saveCursor(const char * name,int line,int pos)450 void hdl_saveCursor(const char *name,int line,int pos)
451 {
452 GModuleDef *M = hdl_active_module;
453
454 if (name) M = env_findModule(name);
455 if (M && M->m_type == MT_TEXTHDL) {
456 ob_touch(M);
457 M->m_curLine = line;
458 M->m_curChar = pos;
459 }
460 }
461
462 /*****************************************************************************
463 *
464 * Get the saved cursor position from the current module
465 *
466 * Parameters:
467 * *line Line number in buffer
468 * *pos Character position on line.
469 *
470 *****************************************************************************/
hdl_getCursor(int * line,int * pos)471 int hdl_getCursor(int *line,int *pos)
472 {
473 GModuleDef *M = hdl_active_module;
474
475 if (!M) return -1;
476 if (M->m_type != MT_TEXTHDL) return -1;
477
478 *line = M->m_curLine;
479 *pos = M->m_curChar;
480
481 return 0;
482 }
483
484 /*****************************************************************************
485 *
486 * Save the current HDL text and end HDL editing.
487 *
488 *****************************************************************************/
hdl_close(void)489 int hdl_close(void)
490 {
491 int rvalue;
492
493 #if 0
494 printf("hdl_close()\n");
495 #endif
496
497 rvalue = hdl_save(0);
498 hdl_active_module = 0;
499 return rvalue;
500 }
501
502