PIPS
emacs.c
Go to the documentation of this file.
1 /*
2 
3  $Id: emacs.c 23065 2016-03-02 09:05:50Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of PIPS.
8 
9  PIPS is free software: you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  PIPS is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with PIPS. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 #ifdef HAVE_CONFIG_H
25  #include "pips_config.h"
26 #endif
27 
28 /* Here are all the stuff to interface Pips with Emacs. */
29 
30 /* Ronan.Keryell@cri.ensmp.fr, 23/05/1995. */
31 
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <strings.h>
36 
37 #include <unistd.h>
38 #include <sys/ioctl.h>
39 #ifndef __linux
40 #include <sys/filio.h>
41 #endif
42 
43 #include <xview/xview.h>
44 #include <xview/panel.h>
45 #include <xview/notify.h>
46 
47 #include "string.h"
48 #include "genC.h"
49 #include "misc.h"
50 #include "linear.h"
51 #include "ri.h"
52 #include "database.h"
53 #include "ri-util.h"
54 #include "pipsdbm.h"
55 #include "properties.h"
56 
57 /* Include the label names: */
58 #include "wpips-labels.h"
59 
60 #include "wpips.h"
61 
62 /* This variable is used to indicate wether wpips is in the Emacs
63  mode: */
64 /* By default, wpips is not called from emacs. RK. */
66 
67 /* The title of the commands used by the emacs interface: */
68 
69 static char EMACS_AVAILABLE_MODULES_NAME[] = "AVAILABLE_MODULES";
70 static char EMACS_MODULE_NAME[] = "MODULE_NAME";
71 static char EMACS_PROMPT_USER[] = "PROMPT_USER";
72 static char EMACS_SEQUENTIAL_VIEW[] = "Sequential View";
73 static char EMACS_USER_ERROR[] = "USER_ERROR";
74 static char EMACS_USER_LOG[] = "USER_LOG";
75 static char EMACS_USER_WARNING[] = "USER_WARNING";
76 static char EMACS_WINDOW_NUMBER[] = "WINDOW_NUMBER";
77 static char EMACS_NEW_DAVINCI_CONTEXT[] = "NEW_DAVINCI_CONTEXT";
78 static char EMACS_VIEW_DAVINCI_GRAPH[] = "VIEW_DAVINCI_GRAPH";
79 
80 /* The token to mark the begin and end of command. Use some strings to
81  be usually never used in ISO-8859-1: */
82 static char epips_begin_of_command_token[] = "\200";
83 static char epips_end_of_command_token[] = "\201";
84 static char epips_receive_begin_of_command_token[] = "\202";
85 static char epips_receive_end_of_command_token[] = "\203";
86 
87 /* At initialization, we are waiting for an input command: */
88 typedef enum
89 {
93 
96 
97 
98 
99 /* Here are described all the functions used to send informations to
100  emacs: */
101 
102 
103 /* Just send some raw text to emacs: */
104 static void
105 send_text_to_emacs(char * some_text)
106 {
107  (void) printf("%s", some_text);
108  fflush(stdout);
109 }
110 
111 
112 /* The function that frames the command to emacs: */
113 static void
114 send_command_to_emacs(char * command_title, char * command_content)
115 {
117  send_text_to_emacs(command_title);
118  /* Separate the command name from the content with a ":" : */
119  send_text_to_emacs(":");
120  send_text_to_emacs(command_content);
122 }
123 
124 
125 /* Here are all the methods used to send an object to Emacs: */
126 
127 void
128 send_module_name_to_emacs(char * some_text)
129 {
131 }
132 
133 
134 /* Tell Emacs about what are the modules available in the current
135  workspace, if any: */
136 void
138 {
139  if (wpips_emacs_mode) {
140  char * module_string_list_string = strdup("(");
141 
142  if (db_get_current_workspace_name() != NULL) {
143  gen_array_t modules = db_get_module_list();
144  int module_list_length = gen_array_nitems(modules), i;
145  for(i = 0; i < module_list_length; i++) {
146  char * new_module_string_list_string =
147  strdup(concatenate(module_string_list_string,
148  "\"", gen_array_item(modules, i), "\" ",
149  NULL));
150  free(module_string_list_string);
151  module_string_list_string = new_module_string_list_string;
152  }
153  gen_array_full_free(modules);
154  }
156  concatenate(module_string_list_string,
157  ")", NULL));
158  free(module_string_list_string);
159  }
160 }
161 
162 
163 void
164 send_prompt_user_to_emacs(char * some_text)
165 {
167 }
168 
169 
170 void
171 send_user_error_to_emacs(char * some_text)
172 {
174 }
175 
176 
177 void
178 send_user_log_to_emacs(char * some_text)
179 {
181 }
182 
183 
184 void
185 send_user_warning_to_emacs(char * some_text)
186 {
188 }
189 
190 
191 void
192 send_view_to_emacs(char * view_name, char * the_file_name)
193 {
194  unsigned int number_of_characters_written;
195  char full_path[1000];
196 
197  /* Send a complete file path since the current directory in Emacs
198  is no the same a priori: */
199  (void) sprintf(full_path, "%s/%s%n", get_cwd(), the_file_name,
200  &number_of_characters_written);
201  pips_assert("send_view_to_emacs",
202  number_of_characters_written < sizeof(full_path));
203 
204  send_command_to_emacs(view_name, full_path);
205 }
206 
207 
208 void
210 {
211  char a_string[10];
212 
213  (void) sprintf(a_string, "%d", number);
215 }
216 
217 
218 
219 void
220 send_notice_prompt_to_emacs(char *first_line, ...)
221 {
222  va_list ap;
223  char * prompt_string;
224 
225  va_start(ap, first_line);
226 
227  send_prompt_user_to_emacs(first_line);
228  while((prompt_string = va_arg(ap, char *)) != NULL)
229  send_prompt_user_to_emacs(prompt_string);
230 
231  va_end(ap);
232 }
233 
234 
235 void
237 {
239 }
240 
241 
242 void
244 {
246 }
247 
248 
249 /* Here are described all the functions used to receive informations
250  from emacs: */
251 
252 
253 /* Emacs said to select a module: */
254 static bool
256 {
257  gen_array_t modules;
258  int new_module_list_length;
259  int module_list_length = 0;
260  int i = 0;
261 
262  if (db_get_current_workspace_name() == NULL) {
263  user_warning("epips_select_module",
264  "No workspace selected or created yet !\n");
265  return FALSE;
266  }
267 
268  modules = db_get_module_list();
269  module_list_length = gen_array_nitems(modules);
270 
271  if (module_list_length == 0)
272  {
273  /* If there is no module... */
274  prompt_user("No module available in this workspace");
275  }
276  else {
277  /* Just to be sure that the selected module exist: */
278  for(i = 0; i < module_list_length; i++) {
279  if (strcmp(module_name, gen_array_item(modules, i)) == 0) {
281  break;
282  }
283  }
284  if (i == module_list_length)
285  user_warning("epips_select_module",
286  "The module \"%s\" does not exist.\n", module_name);
287  }
288  /* args_free zeroes also its length argument... */
289  new_module_list_length = module_list_length;
290  gen_array_full_free(modules);
291 
292  if (module_list_length == 0 || i == module_list_length)
293  /* Something went wrong. */
294  return FALSE;
295 
296  return TRUE;
297 }
298 
299 
300 /* Emacs said to display a sequential view: */
301 static void
303 {
304  bool module_selection_result = TRUE;
305 
306  if (module_name != '\0')
307  /* If module_name is not an empty string, we need to select this
308  module first: */
309  module_selection_result = epips_select_module(module_name);
310 
311  if (module_selection_result)
312  /* Display something only if an eventual module selection has
313  been successful: */
315 }
316 
317 
318 /* Emacs said to display a sequential view: */
319 static void
321 {
323 }
324 
325 
326 static void
328 {
329  char * command_name, * command_content;
330 
331  /* Separate the command name from the content with a ":" : */
332  char * separator_index = (char *) index(command_buffer, ':');
333  debug(2, "epips_execute_command", "Command: \"%s\"\n", command_buffer);
334 
335  if (separator_index == NULL) {
336  user_warning("epips_execute_command",
337  "Cannot understand command: \"%s\"\n", command_buffer);
338  return;
339  }
340 
341  command_name = command_buffer;
342  *separator_index = '\0';
343  command_content = separator_index + 1;
344  debug(2, "epips_execute_command",
345  "command_name: \"%s\", command_content: \"%s\"\n",
346  command_name,
347  command_content);
348 
349  /* Now we can choose what command to execute: */
350  if (strcmp(command_name, EMACS_MODULE_NAME) == 0)
351  epips_select_module(command_content);
352  else if (strcmp(command_name, EMACS_SEQUENTIAL_VIEW) == 0)
353  epips_sequential_view(command_content);
354  else {
355  user_warning("epips_execute_command",
356  "Cannot understand command \"%s\" with argument \"%s\"\n",
357  command_name, command_content);
358  }
359 }
360 
361 
362 static void
363 trow_away_epips_input(char * entry_buffer, long int length)
364 {
365  if (length > 0) {
366  /* By default, send what we do not understand to stderr: */
367  /* I can't remember how to give an argument to %...c ...*/
368  (void) write(fileno(stderr), entry_buffer, length);
369  }
370 }
371 
372 
375 static unsigned int command_buffer_length;
376 
377 
378 /* Copy a part of the entry_buffer in the command_buffer: */
379 static void
380 add_command_to_buffer(char * entry_buffer,
381  unsigned long int length)
382 {
383  pips_assert("add_command_to_buffer in emacs.c: command too big !!!",
384  length + command_buffer_length < sizeof(command_buffer) - 1);
385  (void) memcpy(command_buffer + command_buffer_length,
386  entry_buffer,
387  length);
388  command_buffer_length += length;
390 }
391 
392 
393 /* Try to unframe one half of command sent by emacs. Thus needs an
394  iterator outside. */
395 static char *
396 unframe_commands_from_emacs(char * entry_buffer, long int *length)
397 {
399  /* Wait for a begin of command: */
400  char * epips_packet_begin_position =
401  (char*) index(entry_buffer,
403  debug(8, "unframe_commands_from_emacs",
404  "epips_packet_begin_position = %8X\n", epips_packet_begin_position);
405  if (epips_packet_begin_position == NULL) {
406  /* No begin of command: */
407  trow_away_epips_input(entry_buffer, *length);
408  /* Return an empty string: */
409  entry_buffer += *length;
410  *length = 0;
411  return entry_buffer;
412  }
413  else {
414  /* Discard the begin of buffer: */
415  trow_away_epips_input(entry_buffer,
416  epips_packet_begin_position - entry_buffer);
417  /* Now we wait for an end of command: */
419  /* Empty the command buffer: */
421  /* Skip the begin token: */
422  *length -= epips_packet_begin_position + 1 - entry_buffer;
423  return epips_packet_begin_position + 1;
424  }
425  }
426  else {
427  /* Look for an end of command: */
428  char * epips_packet_end_position =
429  (char*) index(entry_buffer,
431  debug(8, "unframe_commands_from_emacs",
432  "epips_packet_end_position = %8X\n", epips_packet_end_position);
433  if (epips_packet_end_position == NULL) {
434  /* No end of packet found yet. Add the content to the command
435  buffer and keep waiting: */
436  add_command_to_buffer(entry_buffer,
437  *length);
438  entry_buffer += *length;
439  *length = 0;
440  return entry_buffer;
441  }
442  else {
443  add_command_to_buffer(entry_buffer,
444  epips_packet_end_position - entry_buffer);
446  /* Go in the wait for begin state: */
448  /* Skip the end token: */
449  *length -= epips_packet_end_position + 1 - entry_buffer;
450  return epips_packet_end_position + 1;
451  }
452 
453  }
454 }
455 
456 
457 /* The function that accept commands from emacs: */
458 static Notify_value
459 read_commands_from_emacs(Notify_client client, int fd)
460 {
461  char emacs_entry_buffer[1000];
462  long int length;
463 
464  debug_on("EPIPS_DEBUG_LEVEL");
465 
466  if (ioctl(fd, FIONREAD, &length) == -1 || length == 0) {
467  /* Nasty thing. In act, if stdin happens to close (for example I
468  debugged the stuff with wpips -emacs < a), the notifier loop
469  on read_commands_from_emacs(). Thus, in this case, we
470  disinterest the notifier from stdin: */
471  debug(3, "read_commands_from_emacs",
472  "Detach the notifyer from stdin (length to read is %d)\n",
473  length);
474  (void) notify_set_input_func(client,
475  NOTIFY_FUNC_NULL,
476  fileno(stdin));
477  }
478  else {
479  /* We have something to read: */
480  long int read_length;
481  char * entry_buffer = emacs_entry_buffer;
482  do {
483  read_length = read(fd,
484  emacs_entry_buffer,
485  sizeof(emacs_entry_buffer) - 1);
486  if (read_length > 0) {
487  long int analyze_length = read_length;
488 
489  /* OK, we have read something... */
490  emacs_entry_buffer[length] = '\0';
491  debug(9, "read_commands_from_emacs", "Read got \"%s\"\n",
492  emacs_entry_buffer);
493  /* Try to parse until the buffer is empty: */
494  while(*(entry_buffer
495  = unframe_commands_from_emacs(entry_buffer, &analyze_length)) != '\0')
496  debug(8, "unframe_commands_from_emacs", "Return \"%s\"\n",
497  entry_buffer);
498 ;
499  }
500  /* Do not try a blocking read: */
501  } while (read_length > 0 && (length -= read_length) > 0);
502  }
503  debug_off();
504 
505  return NOTIFY_DONE;
506 }
507 
508 
509 /* The function to initialize some things in the emacs mode: */
510 void
512 {
513  if (wpips_emacs_mode) {
514  /* An arbitrary number to identify the notify client function: */
515  Notify_client notifier_client = (Notify_client) 1234;
516 
517  /* The commands from emacs are read from stdin.
518 
519  Thus, we need to register stdin in the XView event Notifier: */
520  (void) notify_set_input_func(notifier_client,
522  fileno(stdin));
523 
524  /* The user query is redirected to Emacs: */
525  /* pips_request_handler = epips_user_request; */
526 
527  /* Initialize the epips.el epips-window-number variable: */
529 
530  /* Ask for Emacs prettyprinting: */
531  set_bool_property("PRETTYPRINT_ADD_EMACS_PROPERTIES", TRUE);
532  /* Ask Pips to display the declarations from the RI to have
533  hypertext functions on the declarations: */
534  set_bool_property("PRETTYPRINT_ALL_DECLARATIONS", TRUE);
535  /* Since the comments of the declarations are not in the RI,
536  pick them in the text: */
537  set_bool_property("PRETTYPRINT_HEADER_COMMENTS", TRUE);
538  }
539 }
size_t gen_array_nitems(const gen_array_t a)
Definition: array.c:131
void gen_array_full_free(gen_array_t a)
Definition: array.c:77
void * gen_array_item(const gen_array_t a, size_t i)
Definition: array.c:143
static unsigned int command_buffer_length
Definition: emacs.c:375
static char EMACS_AVAILABLE_MODULES_NAME[]
The title of the commands used by the emacs interface:
Definition: emacs.c:69
static void epips_execute_command(char *command_buffer)
Definition: emacs.c:327
void initialize_emacs_mode()
The function to initialize some things in the emacs mode:
Definition: emacs.c:511
static bool epips_select_module(char *module_name)
Here are described all the functions used to receive informations from emacs:
Definition: emacs.c:255
void ask_emacs_to_open_a_new_daVinci_context()
Definition: emacs.c:236
void send_the_names_of_the_available_modules_to_emacs(void)
Tell Emacs about what are the modules available in the current workspace, if any:
Definition: emacs.c:137
static void send_command_to_emacs(char *command_title, char *command_content)
The function that frames the command to emacs:
Definition: emacs.c:114
void send_user_error_to_emacs(char *some_text)
Definition: emacs.c:171
static epips_input_automaton_states epips_input_automaton_state
Definition: emacs.c:95
void send_prompt_user_to_emacs(char *some_text)
Definition: emacs.c:164
void ask_emacs_to_display_a_graph(string file_name)
Definition: emacs.c:243
@ EPIPS_COMMAND_BUFFER_SIZE
Definition: emacs.c:373
void send_user_warning_to_emacs(char *some_text)
Definition: emacs.c:185
static char EMACS_MODULE_NAME[]
Definition: emacs.c:70
static char command_buffer[EPIPS_COMMAND_BUFFER_SIZE]
Definition: emacs.c:374
bool wpips_emacs_mode
Here are all the stuff to interface Pips with Emacs.
Definition: emacs.c:65
void send_window_number_to_emacs(int number)
Definition: emacs.c:209
static char EMACS_VIEW_DAVINCI_GRAPH[]
Definition: emacs.c:78
static void epips_sequential_view(char *module_name)
Emacs said to display a sequential view:
Definition: emacs.c:320
epips_input_automaton_states
At initialization, we are waiting for an input command:
Definition: emacs.c:89
@ epips_wait_for_begin
Definition: emacs.c:90
@ epips_wait_for_end
Definition: emacs.c:91
static Notify_value read_commands_from_emacs(Notify_client client, int fd)
The function that accept commands from emacs:
Definition: emacs.c:459
static char epips_begin_of_command_token[]
The token to mark the begin and end of command.
Definition: emacs.c:82
static char epips_end_of_command_token[]
Definition: emacs.c:83
static void trow_away_epips_input(char *entry_buffer, long int length)
Definition: emacs.c:363
static void epips_execute_and_display_something(char *view_label, char *module_name)
Emacs said to display a sequential view:
Definition: emacs.c:302
static char EMACS_PROMPT_USER[]
Definition: emacs.c:71
void send_view_to_emacs(char *view_name, char *the_file_name)
Definition: emacs.c:192
void send_user_log_to_emacs(char *some_text)
Definition: emacs.c:178
void send_module_name_to_emacs(char *some_text)
Here are all the methods used to send an object to Emacs:
Definition: emacs.c:128
static char EMACS_USER_LOG[]
Definition: emacs.c:74
static void send_text_to_emacs(char *some_text)
Here are described all the functions used to send informations to emacs:
Definition: emacs.c:105
static char EMACS_SEQUENTIAL_VIEW[]
Definition: emacs.c:72
static char epips_receive_begin_of_command_token[]
Definition: emacs.c:84
static char EMACS_WINDOW_NUMBER[]
Definition: emacs.c:76
void send_notice_prompt_to_emacs(char *first_line,...)
Definition: emacs.c:220
static void add_command_to_buffer(char *entry_buffer, unsigned long int length)
Copy a part of the entry_buffer in the command_buffer:
Definition: emacs.c:380
static char * unframe_commands_from_emacs(char *entry_buffer, long int *length)
Try to unframe one half of command sent by emacs.
Definition: emacs.c:396
static char epips_receive_end_of_command_token[]
Definition: emacs.c:85
static char EMACS_USER_WARNING[]
Definition: emacs.c:75
static char EMACS_NEW_DAVINCI_CONTEXT[]
Definition: emacs.c:77
static char EMACS_USER_ERROR[]
Definition: emacs.c:73
const char * module_name(const char *s)
Return the module part of an entity name.
Definition: entity_names.c:296
char * get_cwd(void)
returns the current working directory name.
Definition: file.c:486
#define a_string
Definition: genread_lex.c:843
void free(void *)
gen_array_t db_get_module_list(void)
Get an array of all the modules (functions, procedures and compilation units) of a workspace.
Definition: database.c:1266
void prompt_user(string a_printf_format,...)
Definition: gtk_log.c:66
#define debug_on(env)
Definition: misc-local.h:157
#define pips_assert(what, predicate)
common macros, two flavors depending on NDEBUG
Definition: misc-local.h:172
#define debug_off()
Definition: misc-local.h:160
#define user_warning(fn,...)
Definition: misc-local.h:262
void debug(const int the_expected_debug_level, const char *calling_function_name, const char *a_message_format,...)
ARARGS0.
Definition: debug.c:189
string concatenate(const char *,...)
Return the concatenation of the given strings.
Definition: string.c:183
string db_get_current_workspace_name(void)
the function is used to check that there is some current workspace...
Definition: workspace.c:82
void set_bool_property(const char *, bool)
char * strdup()
int printf()
static string file_name
#define INITIAL_NUMBER_OF_WPIPS_WINDOWS
Definition: wpips-local.h:31
void wpips_execute_and_display_something_from_alias(char *alias_name)
To execute something and display some Pips output with wpips or epips by knowing its alias:
Definition: xv_edit2.c:493
void end_select_module_notify(string name)
Definition: xv_select.c:882