1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * VMS port by Henk Elbers
5 * VMS deport by Zoltan Arpadffy
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
52 static TT_MODE orgmode
;
53 static short iochan
; /* TTY I/O channel */
54 static short iosb
[4]; /* IO status block */
56 static int vms_match_num
= 0;
57 static int vms_match_free
= 0;
58 static char_u
**vms_fmatch
= NULL
;
59 static char *Fspec_Rms
; /* rms file spec, passed implicitly between routines */
63 static TT_MODE get_tty
__ARGS((void));
64 static void set_tty
__ARGS((int row
, int col
));
66 #define EXPL_ALLOC_INC 64
68 #define EQN(S1,S2,LN) (strncmp(S1,S2,LN) == 0)
69 #define SKIP_FOLLOWING_SLASHES(Str) while (Str[1] == '/') ++Str
73 * vul_desc vult een descriptor met een string en de lengte
77 vul_desc(DESC
*des
, char *str
)
79 des
->dsc$b_dtype
= DSC$K_DTYPE_T
;
80 des
->dsc$b_class
= DSC$K_CLASS_S
;
81 des
->dsc$a_pointer
= str
;
82 des
->dsc$w_length
= str
? strlen(str
) : 0;
86 * vul_item vult een item met een aantal waarden
89 vul_item(ITEM
*itm
, short len
, short cod
, char *adr
, int *ret
)
98 mch_settmode(int tmode
)
102 if ( tmode
== TMODE_RAW
)
105 switch (orgmode
.width
)
107 case 132: OUT_STR_NF((char_u
*)"\033[?3h\033>"); break;
108 case 80: OUT_STR_NF((char_u
*)"\033[?3l\033>"); break;
112 status
= sys$
qiow(0, iochan
, IO$_SETMODE
, iosb
, 0, 0,
113 &orgmode
, sizeof(TT_MODE
), 0,0,0,0);
114 if (status
!=SS$_NORMAL
|| (iosb
[0]&0xFFFF)!=SS$_NORMAL
)
116 (void)sys$
dassgn(iochan
);
122 set_tty(int row
, int col
)
125 TT_MODE newmode
; /* New TTY mode bits */
126 static short first_time
= TRUE
;
137 newmode
.x
.y
.length
= row
;
138 newmode
.x
.basic
|= (TT$M_NOECHO
| TT$M_HOSTSYNC
);
139 newmode
.x
.basic
&= ~TT$M_TTSYNC
;
140 newmode
.extended
|= TT2$M_PASTHRU
;
141 status
= sys$
qiow(0, iochan
, IO$_SETMODE
, iosb
, 0, 0,
142 &newmode
, sizeof(newmode
), 0, 0, 0, 0);
143 if (status
!=SS$_NORMAL
|| (iosb
[0]&0xFFFF)!=SS$_NORMAL
)
151 static $
DESCRIPTOR(odsc
,"SYS$OUTPUT"); /* output descriptor */
157 status
= sys$
assign(&odsc
,&iochan
,0,0);
159 status
= sys$
qiow(0, iochan
, IO$_SENSEMODE
, iosb
, 0, 0,
160 &tt_mode
, sizeof(tt_mode
), 0, 0, 0, 0);
161 if (status
!= SS$_NORMAL
|| (iosb
[0] & 0xFFFF) != SS$_NORMAL
)
167 tt_mode
.x
.y
.length
= 0;
168 tt_mode
.extended
= 0;
174 * Get the current window size in Rows and Columns.
177 mch_get_shellsize(void)
181 tmode
= get_tty(); /* get size from VMS */
182 Columns
= tmode
.width
;
183 Rows
= tmode
.x
.y
.length
;
188 * Try to set the window size to Rows and new_Columns.
191 mch_set_shellsize(void)
193 set_tty(Rows
, Columns
);
196 case 132: OUT_STR_NF((char_u
*)"\033[?3h\033>"); break;
197 case 80: OUT_STR_NF((char_u
*)"\033[?3l\033>"); break;
205 mch_getenv(char_u
*lognam
)
207 DESC d_file_dev
, d_lognam
;
208 static char buffer
[LNM$C_NAMLENGTH
+1];
210 unsigned long attrib
;
211 int lengte
= 0, dum
= 0, idx
= 0;
215 vul_desc(&d_lognam
, (char *)lognam
);
216 vul_desc(&d_file_dev
, "LNM$FILE_DEV");
217 attrib
= LNM$M_CASE_BLIND
;
218 vul_item(&itmlst
.index
, sizeof(int), LNM$_INDEX
, (char *)&idx
, &dum
);
219 vul_item(&itmlst
.string
, LNM$C_NAMLENGTH
, LNM$_STRING
, buffer
, &lengte
);
221 if (sys$
trnlnm(&attrib
, &d_file_dev
, &d_lognam
, NULL
,&itmlst
) == SS$_NORMAL
)
223 buffer
[lengte
] = '\0';
224 if (cp
= (char_u
*)alloc((unsigned)(lengte
+1)))
225 strcpy((char *)cp
, buffer
);
228 else if ((sbuf
= getenv((char *)lognam
)))
230 lengte
= strlen(sbuf
) + 1;
231 cp
= (char_u
*)malloc((size_t)lengte
);
233 strcpy((char *)cp
, sbuf
);
241 * mch_setenv VMS version of setenv()
244 mch_setenv(char *var
, char *value
, int x
)
248 char acmode
= PSL$C_SUPER
; /* needs SYSNAM privilege */
252 vul_desc(&tabnam
, "LNM$JOB");
253 vul_desc(&lognam
, var
);
254 vul_item(&itmlst
.equ
, value
? strlen(value
) : 0, value
? LNM$_STRING
: 0,
257 res
= sys$
crelnm(&attrib
, &tabnam
, &lognam
, &acmode
, &itmlst
);
258 return((res
== 1) ? 0 : -1);
262 vms_sys(char *cmd
, char *out
, char *inp
)
264 DESC cdsc
, odsc
, idsc
;
268 vul_desc(&cdsc
, cmd
);
270 vul_desc(&odsc
, out
);
272 vul_desc(&idsc
, inp
);
274 lib$
spawn(cmd
? &cdsc
: NULL
, /* command string */
275 inp
? &idsc
: NULL
, /* input file */
276 out
? &odsc
: NULL
, /* output file */
277 0, 0, 0, &status
, 0, 0, 0, 0, 0, 0);
282 * Convert VMS system() or lib$spawn() return code to Unix-like exit value.
285 vms_sys_status(int status
)
287 if (status
!= SS$_NORMAL
&& (status
& STS$M_SUCCESS
) == 0)
288 return status
; /* Command failed. */
294 * function for low level char input
296 * Returns: input length
299 vms_read(char *inbuf
, size_t nbytes
)
301 int status
, function
, len
;
303 ITEM itmlst
[2]; /* terminates on everything */
304 static long trm_mask
[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
306 /* whatever happened earlier we need an iochan here */
310 /* important: clean the inbuf */
311 memset(inbuf
, 0, nbytes
);
313 /* set up the itemlist for the first read */
314 vul_item(&itmlst
[0], 0, TRM$_MODIFIERS
,
315 (char *)( TRM$M_TM_NOECHO
| TRM$M_TM_NOEDIT
|
316 TRM$M_TM_NOFILTR
| TRM$M_TM_TRMNOECHO
|
317 TRM$M_TM_NORECALL
) , 0);
318 vul_item(&itmlst
[1], sizeof(trm_mask
), TRM$_TERM
, (char *)&trm_mask
, 0);
320 /* wait forever for a char */
321 function
= (IO$_READLBLK
| IO$M_EXTEND
);
322 status
= sys$
qiow(0, iochan
, function
, &iosb
, 0, 0,
323 inbuf
, nbytes
-1, 0, 0, &itmlst
, sizeof(itmlst
));
324 len
= strlen(inbuf
); /* how many chars we got? */
326 /* read immediately the rest in the IO queue */
327 function
= (IO$_READLBLK
| IO$M_TIMED
| IO$M_ESCAPE
| IO$M_NOECHO
| IO$M_NOFILTR
);
328 status
= sys$
qiow(0, iochan
, function
, &iosb
, 0, 0,
329 inbuf
+len
, nbytes
-1-len
, 0, 0, 0, 0);
331 len
= strlen(inbuf
); /* return the total length */
337 * vms_wproc() is called for each matching filename by decc$to_vms().
338 * We want to save each match for later retrieval.
340 * Returns: 1 - continue finding matches
341 * 0 - stop trying to find any further matches
344 vms_wproc(char *name
, int val
)
348 static int vms_match_alloced
= 0;
350 if (val
!= DECC$K_FILE
) /* Directories and foreign non VMS files are not
354 if (vms_match_num
== 0) {
355 /* first time through, setup some things */
356 if (NULL
== vms_fmatch
) {
357 vms_fmatch
= (char_u
**)alloc(EXPL_ALLOC_INC
* sizeof(char *));
360 vms_match_alloced
= EXPL_ALLOC_INC
;
361 vms_match_free
= EXPL_ALLOC_INC
;
364 /* re-use existing space */
365 vms_match_free
= vms_match_alloced
;
369 vms_remove_version(name
);
371 /* convert filename to lowercase */
373 for (i
= 0; i
< nlen
; i
++)
374 name
[i
] = TOLOWER_ASC(name
[i
]);
376 /* if name already exists, don't add it */
377 for (i
= 0; i
<vms_match_num
; i
++) {
378 if (0 == STRCMP((char_u
*)name
,vms_fmatch
[i
]))
381 if (--vms_match_free
== 0) {
382 /* add more space to store matches */
383 vms_match_alloced
+= EXPL_ALLOC_INC
;
384 vms_fmatch
= (char_u
**)realloc(vms_fmatch
,
385 sizeof(char **) * vms_match_alloced
);
388 vms_match_free
= EXPL_ALLOC_INC
;
390 vms_fmatch
[vms_match_num
] = vim_strsave((char_u
*)name
);
397 * mch_expand_wildcards this code does wild-card pattern
398 * matching NOT using the shell
400 * return OK for success, FAIL for error (you may lose some
401 * memory) and put an error message in *file.
403 * num_pat number of input patterns
404 * pat array of pointers to input patterns
405 * num_file pointer to number of matched file names
406 * file pointer to array of pointers to matched file names
410 mch_expand_wildcards(int num_pat
, char_u
**pat
, int *num_file
, char_u
***file
, int flags
)
412 int i
, j
= 0, cnt
= 0;
414 char_u buf
[MAXPATHL
];
416 int files_alloced
, files_free
;
418 *num_file
= 0; /* default: no files found */
419 files_alloced
= EXPL_ALLOC_INC
;
420 files_free
= EXPL_ALLOC_INC
;
421 *file
= (char_u
**) alloc(sizeof(char_u
**) * files_alloced
);
427 for (i
= 0; i
< num_pat
; i
++)
429 /* expand environment var or home dir */
430 if (vim_strchr(pat
[i
],'$') || vim_strchr(pat
[i
],'~'))
431 expand_env(pat
[i
],buf
,MAXPATHL
);
435 vms_match_num
= 0; /* reset collection counter */
436 cnt
= decc$
to_vms(decc$
translate_vms(vms_fixfilename(buf
)), vms_wproc
, 1, 0);
437 /* allow wild, no dir */
444 for (i
= 0; i
< cnt
; i
++)
446 /* files should exist if expanding interactively */
447 if (!(flags
& EW_NOTFOUND
) && mch_getperm(vms_fmatch
[i
]) < 0)
450 /* do not include directories */
451 dir
= (mch_isdir(vms_fmatch
[i
]));
452 if (( dir
&& !(flags
& EW_DIR
)) || (!dir
&& !(flags
& EW_FILE
)))
455 /* Skip files that are not executable if we check for that. */
456 if (!dir
&& (flags
& EW_EXEC
) && !mch_can_exe(vms_fmatch
[i
]))
459 /* allocate memory for pointers */
460 if (--files_free
< 1)
462 files_alloced
+= EXPL_ALLOC_INC
;
463 *file
= (char_u
**)realloc(*file
,
464 sizeof(char_u
**) * files_alloced
);
467 *file
= (char_u
**)"";
471 files_free
= EXPL_ALLOC_INC
;
474 (*file
)[*num_file
++] = vms_fmatch
[i
];
481 mch_expandpath(garray_T
*gap
, char_u
*path
, int flags
)
487 cnt
= decc$
to_vms(decc$
translate_vms(vms_fixfilename(path
)), vms_wproc
, 1, 0);
488 /* allow wild, no dir */
491 for (i
= 0; i
< cnt
; i
++)
493 if (mch_getperm(vms_fmatch
[i
]) >= 0) /* add existing file */
494 addfile(gap
, vms_fmatch
[i
], flags
);
500 * attempt to translate a mixed unix-vms file specification to pure vms
503 vms_unix_mixed_filespec(char *in
, char *out
)
510 /* copy vms filename portion up to last colon
513 lastcolon
= strrchr(in
, ':'); /* find last colon */
514 if (lastcolon
!= NULL
) {
515 len
= lastcolon
- in
+ 1;
516 strncpy(out
, in
, len
);
521 end_of_dir
= NULL
; /* default: no directory */
523 /* start of directory portion */
525 if ((ch
== '[') || (ch
== '/') || (ch
== '<')) { /* start of directory(s) ? */
527 SKIP_FOLLOWING_SLASHES(in
);
528 } else if (EQN(in
, "../", 3)) { /* Unix parent directory? */
534 SKIP_FOLLOWING_SLASHES(in
);
535 } else { /* not a special character */
536 while (EQN(in
, "./", 2)) { /* Ignore Unix "current dir" */
538 SKIP_FOLLOWING_SLASHES(in
);
540 if (strchr(in
, '/') == NULL
) { /* any more Unix directories ? */
541 strcpy(out
, in
); /* No - get rest of the spec */
544 *out
++ = '['; /* Yes, denote a Vms subdirectory */
550 /* if we get here, there is a directory part of the filename */
552 /* initialize output file spec */
556 while (*in
!= '\0') {
558 if ((ch
== ']') || (ch
== '/') || (ch
== '>') ) { /* end of (sub)directory ? */
561 SKIP_FOLLOWING_SLASHES(in
);
563 else if (EQN(in
, "../", 3)) { /* Unix parent directory? */
568 SKIP_FOLLOWING_SLASHES(in
);
571 while (EQN(in
, "./", 2)) { /* Ignore Unix "current dir" */
574 SKIP_FOLLOWING_SLASHES(in
);
579 /* Place next character into output file spec */
584 *out
= '\0'; /* Terminate output file spec */
586 if (end_of_dir
!= NULL
) /* Terminate directory portion */
592 * for decc$to_vms in vms_fixfilename
595 vms_fspec_proc(char *fil
, int val
)
597 strcpy(Fspec_Rms
,fil
);
602 * change unix and mixed filenames to VMS
605 vms_fixfilename(void *instring
)
607 static char *buf
= NULL
;
608 static size_t buflen
= 0;
611 /* get a big-enough buffer */
612 len
= strlen(instring
) + 1;
617 buf
= (char *)realloc(buf
, buflen
);
619 buf
= (char *)calloc(buflen
, sizeof(char));
624 tmpbuf
= (char *)calloc(buflen
, sizeof(char));
625 strcpy(tmpbuf
, instring
);
628 Fspec_Rms
= buf
; /* for decc$to_vms */
630 if (strchr(instring
,'/') == NULL
)
631 /* It is already a VMS file spec */
632 strcpy(buf
, instring
);
633 else if (strchr(instring
,'"') == NULL
) /* password in the path? */
635 /* Seems it is a regular file, let guess that it is pure Unix fspec */
636 if (decc$
to_vms(instring
, vms_fspec_proc
, 0, 0) <= 0)
637 /* No... it must be mixed */
638 vms_unix_mixed_filespec(instring
, buf
);
641 /* we have a password in the path */
642 /* decc$ functions can not handle */
643 /* this is our only hope to resolv */
644 vms_unix_mixed_filespec(instring
, buf
);
650 * Remove version number from file name
651 * we need it in some special cases as:
652 * creating swap file name and writing new file
655 vms_remove_version(void * fname
)
660 if ((cp
= vim_strchr( fname
, ';')) != NULL
) /* remove version */
662 else if ((cp
= vim_strrchr( fname
, '.')) != NULL
)
664 if ((fp
= vim_strrchr( fname
, ']')) != NULL
) {;}
665 else if ((fp
= vim_strrchr( fname
, '>')) != NULL
) {;}
668 while ( *fp
!= '\0' && fp
< cp
)