1
/*===========================================================================
2
Copyright (C) 1995-2010 European Southern Observatory (ESO)
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; either version 2 of
7
the License, or (at your option) any later version.
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.
14
You should have received a copy of the GNU General Public
15
License along with this program; if not, write to the Free
16
Software Foundation, Inc., 675 Massachusetts Ave, Cambridge,
19
Correspondence concerning ESO-MIDAS should be addressed as follows:
20
Internet e-mail: midas@eso.org
21
Postal address: European Southern Observatory
22
Data Management Division
23
Karl-Schwarzschild-Strasse 2
24
D 85748 Garching bei Muenchen
26
===========================================================================*/
28
/*+++++++++++++++ MIDAS monitor routines PREPA2 +++++++++++++++++++++++++
30
.IDENTIFICATION Module PREPA2
31
.AUTHOR K. Banse ESO - Garching
32
.KEYWORDS MIDAS monitor
33
.ENVIRONMENT VMS and UNIX
35
synchronize fore- and background processes;
36
get the MIDAS command string + take action accordingly
38
loop on command input (from terminal or procedure file),
39
test for background activity and synchronize
40
system commands are executed directly,
41
all others are executed as command procedures
43
holds Parse3, TTSET, TTINIT, TTEDIT, TTPRO
48
------------------------------------------------------------------------*/
50
#define _POSIX_SOURCE 1 /* indicate that this is a POSIX program */
52
#define OLDTOKMAX 62 /* size of OLDTOKENs is fixed to 64 */
70
#if vms /* FO's terminal stuff only used in VMS */
78
#define EOF (-1) /* End of File */
82
static char blank = {' '};
87
#include <readline/readline.h> /* see changes in re_edit () */
90
#include <osxdef.h> /* MIDAS osx definitions */
91
#include <midback.h> /* Context extructure */
93
extern int is_a_tty; /* Is this a terminal, (yes=1) set in prepa.c */
96
int read_history(), rl_add_funmap_entry();
99
static char contxt_name[MAX_CONTXT*8+2]; /* Activated contexts */
100
static char acknowledge;
101
static char buffer[20]; /* command for xhelp */
102
static char *line_read;
103
static char history_file[200]; /* FRONT.STARTUP+".history."+FRONT.DAZUNIT */
104
static sigjmp_buf env;
109
/* Contains the line to push into readline. */
110
static char *push_to_readline = (char *)NULL;
111
static Function *old_rl_startup_hook = (Function *) NULL;
114
/* Push the contents of push_to_readline into the readline buffer. */
115
static void push_line ()
117
if (push_to_readline)
119
rl_insert_text (push_to_readline);
120
free (push_to_readline);
121
push_to_readline = (char *)NULL;
122
rl_startup_hook = old_rl_startup_hook;
126
/* Call this to set the initial text for the next line to read from readline. */
132
if (push_to_readline)
133
free (push_to_readline);
135
push_to_readline = xmalloc (1 + strlen (line));
136
(void) strcpy (push_to_readline,line);
138
old_rl_startup_hook = rl_startup_hook;
139
rl_startup_hook = (Function *)push_line;
145
char name[12]; /* User printable name of the function */
146
struct COMMAND *prev;
150
struct COMMAND *curr;
151
struct COMMAND *last;
154
extern struct CMD_LIST cmds;
156
static int xhelp_fd = -1;
157
static int xhelp_pid = 0;
158
static char *channame[2] = { (char *)NULL, (char *)NULL };
160
static int initialize_xhelp()
161
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
162
.PURPOSE Initialize channname, containing socket name and
163
filename crated by XHelp.exe containing its pid.
164
It opens a server connection.
165
Initialize the contxt_name string to check for
167
.RETURNS 0 OK, -1 otherwise.
168
------------------------------------------------------------*/
170
char *mid_work, *dazunit;
173
mid_work = getenv("MID_WORK");
175
channame[1] = (char *)
176
malloc((size_t)(strlen(mid_work)+strlen("xhelp")+2+strlen("_pid")+1));
178
dazunit = getenv("DAZUNIT");
180
(void) strcpy(channame[1],mid_work);
181
(void) strcat(channame[1],"xhelp");
182
(void) strcat(channame[1],dazunit);
183
(void) strcat(channame[1],"_pid");
185
n = (int) strlen(channame[1]) - (int) strlen("_pid");
186
channame[0] = (char *) malloc((size_t)(n+1));
187
(void) strncpy(channame[0],channame[1],n);
188
channame[0][n] = '\0';
190
xhelp_fd = osxopen(channame,LOCAL|IPC_READ);
193
(void) printf("\n\rCannot create server for GUI XHelp.exe.\n\r");
194
(void) printf("Error message: %s\n\r",osmsg());
201
/* Initialize the context_name and buffer strings */
202
memset(contxt_name,' ',MAX_CONTXT*8); /* clear context names */
203
memset(buffer,'\0',20); /* Initiate command name */
204
contxt_name[MAX_CONTXT*8] = '\0'; /* make sure we have an end marker */
210
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
211
.PURPOSE Close socket and free allocated memory.
212
This routine is called by prepa.c after the BYE command.
214
------------------------------------------------------------*/
216
if (xhelp_fd != (-1))
218
(void) osxclose(xhelp_fd);
219
(void) free(channame[0]);
220
(void) free(channame[1]);
224
Function *gui_xhelp()
225
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
226
.PURPOSE send messages to the GUI XHELP.
228
------------------------------------------------------------*/
234
if (xhelp_fd == (-1)) return 0;
237
/* retrieve the pid number from XHELP */
239
if ( (fd = fopen(channame[1],"r")) == (FILE *)NULL) {
240
(void) printf("\n\rTry first: CREATE/GUI HELP \n\r");
244
fscanf(fd,(const char *) "%d\n",&xhelp_pid);
246
if (kill(xhelp_pid,0) == -1) {
249
(void) printf("\n\rTry first: CREATE/GUI HELP \n\r");
255
/* Prepare the message to be sent to XHELP not bigger than 12 chars */
256
/* Strip leading blanks */
257
start_buffer = rl_line_buffer;
258
while ( *start_buffer == ' ') start_buffer++;
260
len = strlen(start_buffer);
261
len = (len > 19)? 19 : len;
264
strncpy(buffer,start_buffer,len);
266
if (buffer[len-1] == '/') buffer[len-1] = '\0';
268
/* Check first if CONTEXT list has changed, if so then send USR2 */
269
if (strcmp(contxt_name,CONTXT.NAME)) {
270
(void) strcpy(contxt_name,CONTXT.NAME);
271
/* (void) printf("sending SIGUSR2\n"); */
272
if (osssend(xhelp_pid,SIGUSR2) == -1) {
276
while (osxinfo(xhelp_fd,0,0) == NOCONN) ;
277
/* (void) printf("sending context=%s\n",contxt_name); */
278
if (osxwrite(xhelp_fd,contxt_name,MAX_CONTXT*8 + 2) != MAX_CONTXT*8 + 2)
279
if (osxwrite(xhelp_fd,contxt_name,MAX_CONTXT*8 + 2) != MAX_CONTXT*8 + 2) {
284
if (osxread(xhelp_fd,&acknowledge,1) != 1 && acknowledge != 1) {
291
* Send the message to XHELP , and then interrupt it with USR1 signal.
292
* If error, the connection is broken.
294
/* printf("sending SIGUSR1\n"); */
295
if (osssend(xhelp_pid,SIGUSR1) == -1) {
299
/* printf("osxinfo=%d\n",osxinfo(xhelp_fd,0,0)); */
300
while (osxinfo(xhelp_fd,0,0) == NOCONN) ;
301
/* printf("sending command=%s\n",buffer); */
302
if (osxwrite(xhelp_fd,buffer,20) != 20 )
303
if (osxwrite(xhelp_fd,buffer,20) != 20 ) {
308
if (osxread(xhelp_fd,&acknowledge,1) != 1 && acknowledge != 1) {
315
/* Tell the GNU Readline library how to complete. We want to try to complete
316
* on command names if this is the first word in the line, or on filenames
319
static void initialize_readline()
321
char **fileman_completion();
322
extern Keymap _rl_keymap;
324
if (KIWORDS[OFF_MODE+2] == 0)
326
if (!initialize_xhelp()) {
327
rl_add_funmap_entry("gui-xhelp",gui_xhelp);
328
rl_bind_key('\030',gui_xhelp); /* Bind CTR-X */
329
rl_set_key ("\\e[11~",gui_xhelp,_rl_keymap); /* F1 on Xtectronix and PC */
330
rl_set_key ("\\ep\r",gui_xhelp,_rl_keymap); /* F1 on HPs */
331
rl_set_key ("\\e[[A",gui_xhelp,_rl_keymap); /* F1 on Digital PC */
335
/* Allow conditional parsing of the ~/.inputrc file */
336
rl_readline_name = "MIDAS";
338
/* Tell the completer that we want a crack first */
339
rl_attempted_completion_function = (CPPFunction *)fileman_completion;
341
if (!is_a_tty) rl_outstream = fopen("/dev/null","w");
348
void fileman_ignore(matches)
353
if (!matches) return;
354
for ( i = 0; matches[i]; i++)
355
if ( (ptr = strchr(matches[i], '.')) != (char *)NULL) *ptr = '\0';
361
/* Attempt to complete on the contents of TEXT. START and END show the
362
* region of TEXT that contains the word to complete. We can use the entire
363
* line in case we want to do some simple parsing. Return the array of matches,
364
* or NULL if there aren't any.
366
char **fileman_completion(text, start, end)
371
char *command_generator();
372
char *filename_completion_function();
373
char *curr_dir, *match_dir, *dest_dir;
376
matches = (char **)NULL;
377
match_dir = (char *)NULL;
379
/* If this word is at the start of the line, then it is a command to complete
380
* Otherwise it is the name of a file in the current directory.
382
start_buffer = rl_line_buffer;
383
while ( *start_buffer == ' ') { start_buffer++; start--; }
386
matches = completion_matches(text,command_generator);
387
else if (!strncasecmp(start_buffer,"SHOW/COMM",9) ||
388
!strncasecmp(start_buffer,"HELP ",5) ||
389
!strncasecmp(start_buffer,"DELETE/COMM",11) ||
390
!strncasecmp(start_buffer,"CREATE/COMM",11))
391
matches = completion_matches(text,command_generator);
392
else if (!strncasecmp(start_buffer,"@ " ,2)) match_dir = getenv("MID_PROC");
393
else if (!strncasecmp(start_buffer,"@a ",3)) match_dir = getenv("APP_PROC");
394
else if (!strncasecmp(start_buffer,"@s ",3)) match_dir = getenv("STD_PROC");
395
else if (!strncasecmp(start_buffer,"@c ",3)) match_dir = getenv("CON_PROC");
396
else if (!strncasecmp(start_buffer,"LOAD/LUT ",9) ||
397
!strncasecmp(start_buffer,"LOAD/ITT ",9))
398
match_dir = getenv("MID_SYSTAB");
399
else if (!strncasecmp(start_buffer,"SET/CONT",8) ||
400
!strncasecmp(start_buffer,"CLEAR/CONT",10) ||
401
!strncasecmp(start_buffer,"SHOW/CONT",10))
402
match_dir = getenv("MID_CONTEXT");
403
else if (!strncasecmp(start_buffer,"CREATE/GUI ",11))
404
match_dir = getenv("GUI_EXE");
406
if (match_dir != (char *)NULL) {
407
dest_dir = malloc((size_t)(strlen(match_dir)+1));
408
(void) strcpy(dest_dir,match_dir);
409
oshgetcwd(&curr_dir);
411
matches = completion_matches(text,filename_completion_function);
415
if (!strncasecmp(start_buffer,"SET/CONT",8) ||
416
!strncasecmp(start_buffer,"CLEAR/CONT",10) ||
417
!strncasecmp(start_buffer,"CREATE/GUI ",11)) fileman_ignore(matches);
426
* Generator fucntion for command completion. STATE lets us know weather
427
* to start from scratch; without any state (i.e. STATE =0), then we start
428
* at the top of the list
430
char *command_generator(text, state)
435
static char mytext[12];
436
static char *ptr_text;
437
register struct COMMAND *mycmd;
438
register char *slash_ptr;
439
register int len_cmd, max_len_cmd, len_qua;
442
* If this is a new word to complete, initialize now. This includes
443
* saving the length of TEXT for efficiency, an initializing the index
447
if (MONIT.CMD_LIST_UPDA == 1) /* commands have been modified... */
453
if ((slash_ptr = (char *)strchr(text,'/')) != (char *)NULL) {
454
len_cmd = (long)slash_ptr - (long)text;
455
max_len_cmd = (len_cmd > 6)? 6 : len_cmd;
456
(void) strncpy(mytext,text,max_len_cmd);
457
mytext[max_len_cmd] = '/';
458
mytext[max_len_cmd+1] = '\0';
459
len_qua = strlen(&text[len_cmd+1]);
460
(void) strncat(mytext,&text[len_cmd+1],(len_qua > 4)? 4 : len_qua);
461
len = strlen(mytext);
465
len = (len > 6)? 6 : len;
466
(void) strncpy(mytext,text,len);
470
cmds.curr = cmds.last;
473
/* Return the next name which partially matches from the command list. */
474
while ((mycmd = cmds.curr) != (struct COMMAND *)NULL) {
475
cmds.curr = mycmd->prev;
476
if (strncasecmp(mycmd->name,ptr_text,len) == 0)
478
((char *)strcpy((malloc((size_t)(strlen(mycmd->name)+1))),mycmd->name));
481
/* If no names matched, then return NULL */
482
return((char *)NULL);
488
static void TTPRO_alarm(int sig)
490
static void TTPRO_alarm(sig)
492
.PURPOSE Function called at end of time-out
493
.RETURNS Within ostread function. Internal use only.
498
siglongjmp(env,1); /* return with the saved signal mask from sigsetjmp */
500
#endif /* NO_READLINE */
507
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
512
return no. of tokens on line
513
---------------------------------------------------------------------*/
519
int n, count, substi, kk, nn, mm;
522
char wbuf[MAX_TOKEN];
527
/* extract all tokens + get their length, also use OLD_TOKEN */
535
CGN_EXTRSS(LINE.STR,LINE.LEN,blank,&lstart,TOKEN[n].STR,MAX_TOKEN);
536
if (TOKEN[n].LEN <= 0) /* end of parsing reached... */
538
if (TOKEN[n].LEN == -2) /* overflow of single token */
541
PREPERR("MIDAS",LINE.STR,TOKEN[n].STR);
546
for (nr=count; nr<10; nr++)
548
TOKEN[nr].STR[0] = '?'; /* init empty TOKEN + LTOKEN */
549
TOKEN[nr].STR[1] = '\0' ;
556
/* test for interactive input with "." */
558
if ( (TOKEN[n].STR[0] == '.') && (TOKEN[n].LEN == 1) )
560
TOKEN[n].LEN = CGN_COPY(TOKEN[n].STR,OLDTOKEN[n].STR);
561
substi = 1 ; /* it's like a substitution */
565
sngc = TOKEN[n].STR[OLDTOKMAX]; /* save char. */
566
TOKEN[n].STR[OLDTOKMAX] = '\0'; /* so, no overrun... */
567
OLDTOKEN[n].LEN = CGN_COPY(OLDTOKEN[n].STR,TOKEN[n].STR);
568
TOKEN[n].STR[OLDTOKMAX] = sngc;
575
/* test, if more than 10 tokens on line */
577
if (LINE.LEN >= lstart)
579
for (nr=lstart; nr<LINE.LEN; nr++)
581
if (LINE.STR[nr] != ' ') goto collect_rest;
583
goto end_of_it; /* only trailing blanks */
589
for (nr=0; nr< 39; nr++) /* garbage collection of 40 more tokens... */
591
lsave = CGN_EXTRSS(LINE.STR,LINE.LEN,blank,&lstart,wbuf,MAX_TOKEN);
594
if ((lsave+nn+1) > MAX_TOKEN)
601
TOKEN[9].STR[nn++] = ' ';
604
(void) strncpy(&TOKEN[9].STR[nn],wbuf,mm);
610
TOKEN[9].STR[nn] = '\0' ;
615
if (substi > 0) /* rebuild input line */
620
for (nr=0; nr<count; nr++)
622
(void) strncpy(&LINE.STR[indx],TOKEN[nr].STR,TOKEN[nr].LEN);
623
indx += TOKEN[nr].LEN;
624
LINE.STR[indx++] = ' ';
625
if (indx >= MAX_LINE)
628
PREPERR("MIDAS",LINE.STR," ");
632
LINE.STR[--indx] = '\0'; /* last blank -> \0 */
644
void TTSET(flg) /* only used in VMS */
646
int flg; /* IN: 0 = clear, 1 = set terminal, 2 = byebye */
653
ostraw(flg); /* clear/set terminal settings */
657
CloseTerm(); /* reset terminal completely */
671
/*++++++++++++++++++++++++++++++++++++++++++++++++++
677
open foreground window only
680
--------------------------------------------------*/
682
int hdr; /* IN: header flag = 0 (no) or = 1 (yes) */
686
#if vms /* --- here for VMS --- */
690
/* TERM.FLAG = 0/1 for TermWindow use (only for VMS!) */
693
{ /* (device,termcapfile,control_chars */
694
n = OpenTerm((char *) 0,(char *) 0,TW_cc_VMS);
712
(void) strncpy(history_file,FRONT.STARTUP,80);
713
(void) strcat(history_file,"midtemp");
714
(void) strncat(history_file,FRONT.DAZUNIT,2);
715
(void) strcat(history_file,".prg");
717
read_history(history_file);
718
initialize_readline (); /* Bind our completer */
721
#endif /* endif NO_READLINE */
724
#else /* --- here for Unix/Linux --- */
727
(void) strncpy(history_file,FRONT.STARTUP,80);
728
(void) strcat(history_file,"midtemp");
729
(void) strncat(history_file,FRONT.DAZUNIT,2);
730
(void) strcat(history_file,".prg");
732
read_history(history_file);
733
initialize_readline (); /* Bind our completer */
735
#endif /* endif NO_READLINE */
738
#endif /* endif vms */
744
if (FRONT.TITLE[0] == 'F')
746
(void) strcpy(wstr," FrontEnd to MIDAS ");
750
(void) strcpy(wstr," ESO-MIDAS version ");
751
(void) strcat(wstr,&FRONT.TITLE[1]);
752
(void) strcat(wstr," on ");
753
FRONT.SYSTEM[19] = '\0';
754
(void) strcat(wstr,FRONT.SYSTEM);
755
FRONT.SYSTEM[19] = ' ';
757
(void) printf("\n\n\r%s\n\r",wstr);
761
/* get new size of terminal window */
763
MID_TTINFO(&TERM.COLS,&TERM.LINES);
770
CursorTo(n,0); /* move cursor to lower left corner */
781
/*++++++++++++++++++++++++++++++++++++++++++++++++++
787
use FO's window interfaces
790
--------------------------------------------------*/
792
char *line; /* IN/OUT: line to be edited (terminated by \0) */
793
int len; /* IN: max. length of 'line' */
797
struct sigaction act, oact;
803
if (TERM.FLAG != 0) /* we use FO's termwin stuff */
807
MID_TTINFO(&TERM.COLS,&TERM.LINES); /* get new size of terminal window */
809
CursorTo(n,0); /* move cursor to lower left corner */
811
status = tv_kmods(TERM.EDITMODE,line,len,strlen(line));
812
if (status != OK) return (-1);
817
#endif /* endif vms */
820
/* for TERM.FLAG = 0 (as in Unix) check, if we use readline library */
824
line_read = (char *)NULL;
825
act.sa_handler = TTPRO_alarm;
826
sigemptyset(&act.sa_mask);
828
(void) sigaction(SIGALRM,&act,&oact);
830
if ( sigsetjmp(env,1) == 0 )
833
line_read = readline("");
834
if (line_read && *line_read)
836
(void) strcpy(line,line_read); /* before: add_history(line_read); */
837
free(line_read); /* before: */
843
(void) sigaction(SIGALRM,&oact,&act);
847
(void) printf("%s\n\r",line);
858
void TTPRO(prompt,line,len)
860
/*++++++++++++++++++++++++++++++++++++++++++++++++++
864
prompt for + get an input line from windows
866
use FO's window interfaces
869
--------------------------------------------------*/
871
char *prompt; /* IN: prompt string (terminated by \0) */
872
char *line; /* OUT: input line (terminated by \0) */
873
int len; /* IN: length of buffer 'line' */
877
struct sigaction act, oact;
887
if (TERM.FLAG != 0) /* we use FO's termwin stuff */
894
n = tv_kmods(TERM.EDITMODE,line,len,0);
897
/* interrupt routine `intermail' sets TERM.TIMEOUT to 2 */
899
if (TERM.TIMEOUT == 0)
901
if (n == EOF) (void) strcpy(line,"BYE");
907
#endif /* endif vms */
910
/* for TERM.FLAG = 0 (as in Unix) check, if we use readline library */
914
line_read = (char *)NULL;
915
act.sa_handler = TTPRO_alarm;
916
sigemptyset(&act.sa_mask);
918
(void) sigaction(SIGALRM,&act,&oact);
920
if ( sigsetjmp(env,1) == 0 )
923
line_read = readline(prompt);
925
line_read = readline("");
931
(void) strcpy(line,line_read); /* before: add_history(line_read); */
932
free(line_read); /* before: */
937
(void) strcpy(line,"bye");
939
(void) sigaction(SIGALRM,&oact,&act);
943
(void) printf("%s ",prompt);
944
(void) CGN_GETLINE(line,len);