blob: 0a67a6b75d0e0fa5ca17451577facb04d0b87381 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * VMS port by Henk Elbers
5 * VMS deport by Zoltan Arpadffy
6 *
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.
10 */
11
12#include "vim.h"
13
Bram Moolenaar0f873732019-12-05 20:28:46 +010014// define _generic_64 for use in time functions
Bram Moolenaarb8e0bdb2014-11-12 16:10:48 +010015#if !defined(VAX) && !defined(PROTO)
Bram Moolenaar4ffa0702013-12-11 17:12:37 +010016# include <gen64def.h>
17#else
Bram Moolenaar0f873732019-12-05 20:28:46 +010018// based on Alpha's gen64def.h; the file is absent on VAX
Bram Moolenaar4ffa0702013-12-11 17:12:37 +010019typedef struct _generic_64 {
20# pragma __nomember_alignment
Bram Moolenaar0f873732019-12-05 20:28:46 +010021 __union { // You can treat me as...
22 // long long is not available on VAXen
23 // unsigned __int64 gen64$q_quadword; ...a single 64-bit value, or
Bram Moolenaar4ffa0702013-12-11 17:12:37 +010024
Bram Moolenaar0f873732019-12-05 20:28:46 +010025 unsigned int gen64$l_longword [2]; // ...two 32-bit values, or
26 unsigned short int gen64$w_word [4]; // ...four 16-bit values
Bram Moolenaar4ffa0702013-12-11 17:12:37 +010027 } gen64$r_quad_overlay;
28} GENERIC_64;
29#endif
30
Bram Moolenaar071d4272004-06-13 20:20:40 +000031typedef struct
32{
33 char class;
34 char type;
35 short width;
36 union
37 {
38 struct
39 {
40 char _basic[3];
41 char length;
42 } y;
43 int basic;
44 } x;
45 int extended;
46} TT_MODE;
47
48typedef struct
49{
50 short buflen;
51 short itemcode;
52 char *bufadrs;
53 int *retlen;
54} ITEM;
55
56typedef struct
57{
58 ITEM equ;
59 int nul;
60} ITMLST1;
61
62typedef struct
63{
64 ITEM index;
65 ITEM string;
66 int nul;
67} ITMLST2;
68
69static TT_MODE orgmode;
Bram Moolenaar0f873732019-12-05 20:28:46 +010070static short iochan; // TTY I/O channel
71static short iosb[4]; // IO status block
Bram Moolenaar071d4272004-06-13 20:20:40 +000072
73static int vms_match_num = 0;
74static int vms_match_free = 0;
75static char_u **vms_fmatch = NULL;
Bram Moolenaar0f873732019-12-05 20:28:46 +010076static char *Fspec_Rms; // rms file spec, passed implicitly between routines
Bram Moolenaar071d4272004-06-13 20:20:40 +000077
78
79
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010080static TT_MODE get_tty(void);
81static void set_tty(int row, int col);
Bram Moolenaar071d4272004-06-13 20:20:40 +000082
83#define EXPL_ALLOC_INC 64
84
85#define EQN(S1,S2,LN) (strncmp(S1,S2,LN) == 0)
Bram Moolenaar6f470022018-04-10 18:47:20 +020086#define SKIP_FOLLOWING_SLASHES(Str) do { while (Str[1] == '/') ++Str; } while (0)
Bram Moolenaar071d4272004-06-13 20:20:40 +000087
88
89/*
90 * vul_desc vult een descriptor met een string en de lengte
91 * hier van.
92 */
93 static void
94vul_desc(DESC *des, char *str)
95{
96 des->dsc$b_dtype = DSC$K_DTYPE_T;
97 des->dsc$b_class = DSC$K_CLASS_S;
98 des->dsc$a_pointer = str;
99 des->dsc$w_length = str ? strlen(str) : 0;
100}
101
102/*
103 * vul_item vult een item met een aantal waarden
104 */
105 static void
106vul_item(ITEM *itm, short len, short cod, char *adr, int *ret)
107{
108 itm->buflen = len;
109 itm->itemcode = cod;
110 itm->bufadrs = adr;
111 itm->retlen = ret;
112}
113
114 void
Bram Moolenaar26e86442020-05-17 14:06:16 +0200115mch_settmode(tmode_T tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116{
117 int status;
118
119 if ( tmode == TMODE_RAW )
120 set_tty(0, 0);
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000121 else
122 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000123 switch (orgmode.width)
124 {
125 case 132: OUT_STR_NF((char_u *)"\033[?3h\033>"); break;
126 case 80: OUT_STR_NF((char_u *)"\033[?3l\033>"); break;
127 default: break;
128 }
129 out_flush();
130 status = sys$qiow(0, iochan, IO$_SETMODE, iosb, 0, 0,
131 &orgmode, sizeof(TT_MODE), 0,0,0,0);
132 if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
133 return;
134 (void)sys$dassgn(iochan);
135 iochan = 0;
136 }
137}
138
139 static void
140set_tty(int row, int col)
141{
142 int status;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100143 TT_MODE newmode; // New TTY mode bits
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144 static short first_time = TRUE;
145
146 if (first_time)
147 {
148 orgmode = get_tty();
149 first_time = FALSE;
150 }
151 newmode = get_tty();
152 if (col)
153 newmode.width = col;
154 if (row)
155 newmode.x.y.length = row;
156 newmode.x.basic |= (TT$M_NOECHO | TT$M_HOSTSYNC);
157 newmode.x.basic &= ~TT$M_TTSYNC;
158 newmode.extended |= TT2$M_PASTHRU;
159 status = sys$qiow(0, iochan, IO$_SETMODE, iosb, 0, 0,
160 &newmode, sizeof(newmode), 0, 0, 0, 0);
161 if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
162 return;
163}
164
165 static TT_MODE
166get_tty(void)
167{
168
Bram Moolenaar0f873732019-12-05 20:28:46 +0100169 static $DESCRIPTOR(odsc,"SYS$OUTPUT"); // output descriptor
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
171 int status;
172 TT_MODE tt_mode;
173
174 if (!iochan)
175 status = sys$assign(&odsc,&iochan,0,0);
176
177 status = sys$qiow(0, iochan, IO$_SENSEMODE, iosb, 0, 0,
178 &tt_mode, sizeof(tt_mode), 0, 0, 0, 0);
179 if (status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL)
180 {
181 tt_mode.width = 0;
182 tt_mode.type = 0;
183 tt_mode.class = 0;
184 tt_mode.x.basic = 0;
185 tt_mode.x.y.length = 0;
186 tt_mode.extended = 0;
187 }
188 return(tt_mode);
189}
190
191/*
192 * Get the current window size in Rows and Columns.
193 */
194 int
195mch_get_shellsize(void)
196{
197 TT_MODE tmode;
198
Bram Moolenaar0f873732019-12-05 20:28:46 +0100199 tmode = get_tty(); // get size from VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200 Columns = tmode.width;
201 Rows = tmode.x.y.length;
202 return OK;
203}
204
205/*
206 * Try to set the window size to Rows and new_Columns.
207 */
208 void
209mch_set_shellsize(void)
210{
211 set_tty(Rows, Columns);
212 switch (Columns)
213 {
214 case 132: OUT_STR_NF((char_u *)"\033[?3h\033>"); break;
215 case 80: OUT_STR_NF((char_u *)"\033[?3l\033>"); break;
216 default: break;
217 }
218 out_flush();
219 screen_start();
220}
221
222 char_u *
223mch_getenv(char_u *lognam)
224{
225 DESC d_file_dev, d_lognam ;
226 static char buffer[LNM$C_NAMLENGTH+1];
227 char_u *cp = NULL;
228 unsigned long attrib;
229 int lengte = 0, dum = 0, idx = 0;
230 ITMLST2 itmlst;
231 char *sbuf = NULL;
232
233 vul_desc(&d_lognam, (char *)lognam);
234 vul_desc(&d_file_dev, "LNM$FILE_DEV");
235 attrib = LNM$M_CASE_BLIND;
236 vul_item(&itmlst.index, sizeof(int), LNM$_INDEX, (char *)&idx, &dum);
237 vul_item(&itmlst.string, LNM$C_NAMLENGTH, LNM$_STRING, buffer, &lengte);
238 itmlst.nul = 0;
239 if (sys$trnlnm(&attrib, &d_file_dev, &d_lognam, NULL,&itmlst) == SS$_NORMAL)
240 {
241 buffer[lengte] = '\0';
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200242 if (cp = alloc(lengte + 1))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 strcpy((char *)cp, buffer);
244 return(cp);
245 }
246 else if ((sbuf = getenv((char *)lognam)))
247 {
248 lengte = strlen(sbuf) + 1;
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200249 cp = alloc(lengte);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000250 if (cp)
251 strcpy((char *)cp, sbuf);
252 return cp;
253 }
254 else
255 return(NULL);
256}
257
258/*
259 * mch_setenv VMS version of setenv()
260 */
261 int
262mch_setenv(char *var, char *value, int x)
263{
264 int res, dum;
265 long attrib = 0L;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100266 char acmode = PSL$C_SUPER; // needs SYSNAM privilege
Bram Moolenaar071d4272004-06-13 20:20:40 +0000267 DESC tabnam, lognam;
268 ITMLST1 itmlst;
269
270 vul_desc(&tabnam, "LNM$JOB");
271 vul_desc(&lognam, var);
272 vul_item(&itmlst.equ, value ? strlen(value) : 0, value ? LNM$_STRING : 0,
273 value, &dum);
274 itmlst.nul = 0;
275 res = sys$crelnm(&attrib, &tabnam, &lognam, &acmode, &itmlst);
276 return((res == 1) ? 0 : -1);
277}
278
279 int
280vms_sys(char *cmd, char *out, char *inp)
281{
282 DESC cdsc, odsc, idsc;
283 long status;
284
285 if (cmd)
286 vul_desc(&cdsc, cmd);
287 if (out)
288 vul_desc(&odsc, out);
289 if (inp)
290 vul_desc(&idsc, inp);
291
Bram Moolenaar0f873732019-12-05 20:28:46 +0100292 lib$spawn(cmd ? &cdsc : NULL, // command string
293 inp ? &idsc : NULL, // input file
294 out ? &odsc : NULL, // output file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 0, 0, 0, &status, 0, 0, 0, 0, 0, 0);
296 return status;
297}
298
299/*
Bram Moolenaar206f0112014-03-12 16:51:55 +0100300 * Convert string to lowercase - most often filename
301 */
302 char *
303vms_tolower( char *name )
304{
305 int i,nlen = strlen(name);
306 for (i = 0; i < nlen; i++)
307 name[i] = TOLOWER_ASC(name[i]);
308 return name;
309}
310
311/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312 * Convert VMS system() or lib$spawn() return code to Unix-like exit value.
313 */
314 int
315vms_sys_status(int status)
316{
317 if (status != SS$_NORMAL && (status & STS$M_SUCCESS) == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100318 return status; // Command failed.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 return 0;
320}
321
322/*
323 * vms_read()
324 * function for low level char input
325 *
326 * Returns: input length
327 */
328 int
329vms_read(char *inbuf, size_t nbytes)
330{
Bram Moolenaara83c3e02006-03-17 23:10:44 +0000331 int status, function, len;
332 TT_MODE tt_mode;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100333 ITEM itmlst[2]; // terminates on everything
Bram Moolenaar071d4272004-06-13 20:20:40 +0000334 static long trm_mask[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
335
Bram Moolenaar0f873732019-12-05 20:28:46 +0100336 // whatever happened earlier we need an iochan here
Bram Moolenaar071d4272004-06-13 20:20:40 +0000337 if (!iochan)
Bram Moolenaara83c3e02006-03-17 23:10:44 +0000338 tt_mode = get_tty();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000339
Bram Moolenaar0f873732019-12-05 20:28:46 +0100340 // important: clean the inbuf
Bram Moolenaar071d4272004-06-13 20:20:40 +0000341 memset(inbuf, 0, nbytes);
342
Bram Moolenaar0f873732019-12-05 20:28:46 +0100343 // set up the itemlist for the first read
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000344 vul_item(&itmlst[0], 0, TRM$_MODIFIERS,
Bram Moolenaara83c3e02006-03-17 23:10:44 +0000345 (char *)( TRM$M_TM_NOECHO | TRM$M_TM_NOEDIT |
346 TRM$M_TM_NOFILTR | TRM$M_TM_TRMNOECHO |
347 TRM$M_TM_NORECALL) , 0);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000348 vul_item(&itmlst[1], sizeof(trm_mask), TRM$_TERM, (char *)&trm_mask, 0);
349
Bram Moolenaar0f873732019-12-05 20:28:46 +0100350 // wait forever for a char
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000351 function = (IO$_READLBLK | IO$M_EXTEND);
352 status = sys$qiow(0, iochan, function, &iosb, 0, 0,
Bram Moolenaara83c3e02006-03-17 23:10:44 +0000353 inbuf, nbytes-1, 0, 0, &itmlst, sizeof(itmlst));
Bram Moolenaar0f873732019-12-05 20:28:46 +0100354 len = strlen(inbuf); // how many chars we got?
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000355
Bram Moolenaar0f873732019-12-05 20:28:46 +0100356 // read immediately the rest in the IO queue
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000357 function = (IO$_READLBLK | IO$M_TIMED | IO$M_ESCAPE | IO$M_NOECHO | IO$M_NOFILTR);
358 status = sys$qiow(0, iochan, function, &iosb, 0, 0,
Bram Moolenaara83c3e02006-03-17 23:10:44 +0000359 inbuf+len, nbytes-1-len, 0, 0, 0, 0);
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000360
Bram Moolenaar0f873732019-12-05 20:28:46 +0100361 len = strlen(inbuf); // return the total length
Bram Moolenaar5e3cb7e2006-02-27 23:58:35 +0000362
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 return len;
364}
365
366/*
367 * vms_wproc() is called for each matching filename by decc$to_vms().
368 * We want to save each match for later retrieval.
369 *
370 * Returns: 1 - continue finding matches
Bram Moolenaar82038d72007-05-10 17:15:45 +0000371 * 0 - stop trying to find any further matches
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372 */
373 static int
374vms_wproc(char *name, int val)
375{
376 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 static int vms_match_alloced = 0;
378
Bram Moolenaar0f873732019-12-05 20:28:46 +0100379 if (val == DECC$K_FOREIGN ) // foreign non VMS files are not counting
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380 return 1;
381
Bram Moolenaar0f873732019-12-05 20:28:46 +0100382 // accept all DECC$K_FILE and DECC$K_DIRECTORY
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000383 if (vms_match_num == 0)
384 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100385 // first time through, setup some things
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000386 if (NULL == vms_fmatch)
387 {
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +0100388 vms_fmatch = ALLOC_MULT(char_u *, EXPL_ALLOC_INC);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 if (!vms_fmatch)
390 return 0;
391 vms_match_alloced = EXPL_ALLOC_INC;
392 vms_match_free = EXPL_ALLOC_INC;
393 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000394 else
395 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100396 // re-use existing space
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 vms_match_free = vms_match_alloced;
398 }
399 }
400
Bram Moolenaar0f873732019-12-05 20:28:46 +0100401 // make matches look uniform
Bram Moolenaar071d4272004-06-13 20:20:40 +0000402 vms_remove_version(name);
Bram Moolenaar206f0112014-03-12 16:51:55 +0100403 name=vms_tolower(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404
Bram Moolenaar0f873732019-12-05 20:28:46 +0100405 // if name already exists, don't add it
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000406 for (i = 0; i<vms_match_num; i++)
407 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 if (0 == STRCMP((char_u *)name,vms_fmatch[i]))
409 return 1;
410 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000411 if (--vms_match_free == 0)
412 {
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100413 char_u **old_vms_fmatch = vms_fmatch;
414
Bram Moolenaar0f873732019-12-05 20:28:46 +0100415 // add more space to store matches
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 vms_match_alloced += EXPL_ALLOC_INC;
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100417 vms_fmatch = vim_realloc(old_vms_fmatch,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 sizeof(char **) * vms_match_alloced);
419 if (!vms_fmatch)
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100420 {
421 vim_free(old_vms_fmatch);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 return 0;
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100423 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 vms_match_free = EXPL_ALLOC_INC;
425 }
426 vms_fmatch[vms_match_num] = vim_strsave((char_u *)name);
427
428 ++vms_match_num;
429 return 1;
430}
431
432/*
433 * mch_expand_wildcards this code does wild-card pattern
434 * matching NOT using the shell
435 *
Bram Moolenaare37d50a2008-08-06 17:06:04 +0000436 * return OK for success, FAIL for error (you may lose some
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 * memory) and put an error message in *file.
438 *
439 * num_pat number of input patterns
440 * pat array of pointers to input patterns
441 * num_file pointer to number of matched file names
442 * file pointer to array of pointers to matched file names
443 *
444 */
445 int
446mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)
447{
Bram Moolenaar64404472010-06-26 06:24:45 +0200448 int i, cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449 char_u buf[MAXPATHL];
Bram Moolenaar206f0112014-03-12 16:51:55 +0100450 char *result;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451 int dir;
452 int files_alloced, files_free;
453
Bram Moolenaar0f873732019-12-05 20:28:46 +0100454 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455 files_alloced = EXPL_ALLOC_INC;
456 files_free = EXPL_ALLOC_INC;
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +0100457 *file = ALLOC_MULT(char_u *, files_alloced);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458 if (*file == NULL)
459 {
460 *num_file = 0;
461 return FAIL;
462 }
463 for (i = 0; i < num_pat; i++)
464 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100465 // expand environment var or home dir
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 if (vim_strchr(pat[i],'$') || vim_strchr(pat[i],'~'))
467 expand_env(pat[i],buf,MAXPATHL);
468 else
469 STRCPY(buf,pat[i]);
470
Bram Moolenaar0f873732019-12-05 20:28:46 +0100471 vms_match_num = 0; // reset collection counter
Bram Moolenaar206f0112014-03-12 16:51:55 +0100472 result = decc$translate_vms(vms_fixfilename(buf));
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000473 if ( (int) result == 0 || (int) result == -1 )
474 {
Bram Moolenaar206f0112014-03-12 16:51:55 +0100475 cnt = 0;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000476 }
477 else
478 {
Bram Moolenaar206f0112014-03-12 16:51:55 +0100479 cnt = decc$to_vms(result, vms_wproc, 1 /*allow wild*/ , (flags & EW_DIR ? 0:1 ) /*allow directory*/) ;
480 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481 if (cnt > 0)
482 cnt = vms_match_num;
483
484 if (cnt < 1)
485 continue;
486
487 for (i = 0; i < cnt; i++)
488 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100489 // files should exist if expanding interactively
Bram Moolenaar071d4272004-06-13 20:20:40 +0000490 if (!(flags & EW_NOTFOUND) && mch_getperm(vms_fmatch[i]) < 0)
491 continue;
Bram Moolenaara2031822006-03-07 22:29:51 +0000492
Bram Moolenaar0f873732019-12-05 20:28:46 +0100493 // do not include directories
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494 dir = (mch_isdir(vms_fmatch[i]));
495 if (( dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
496 continue;
Bram Moolenaara2031822006-03-07 22:29:51 +0000497
Bram Moolenaar0f873732019-12-05 20:28:46 +0100498 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +0100499 if (!dir && (flags & EW_EXEC)
500 && !mch_can_exe(vms_fmatch[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +0000501 continue;
502
Bram Moolenaar0f873732019-12-05 20:28:46 +0100503 // allocate memory for pointers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 if (--files_free < 1)
505 {
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100506 char_u **old_file = *file;
507
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 files_alloced += EXPL_ALLOC_INC;
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100509 *file = vim_realloc(old_file, sizeof(char_u **) * files_alloced);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 if (*file == NULL)
511 {
Bram Moolenaar9625d3d2019-11-30 22:57:53 +0100512 vim_free(old_file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 *file = (char_u **)"";
514 *num_file = 0;
515 return(FAIL);
516 }
517 files_free = EXPL_ALLOC_INC;
518 }
519
520 (*file)[*num_file++] = vms_fmatch[i];
521 }
522 }
523 return OK;
524}
525
526 int
527mch_expandpath(garray_T *gap, char_u *path, int flags)
528{
529 int i,cnt = 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +0100530 char *result;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000531
Bram Moolenaar206f0112014-03-12 16:51:55 +0100532 vms_match_num = 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100533 // the result from the decc$translate_vms needs to be handled
534 // otherwise it might create ACCVIO error in decc$to_vms
Bram Moolenaar206f0112014-03-12 16:51:55 +0100535 result = decc$translate_vms(vms_fixfilename(path));
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000536 if ( (int) result == 0 || (int) result == -1 )
537 {
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100538 cnt = 0;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000539 }
540 else
541 {
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100542 cnt = decc$to_vms(result, vms_wproc, 1 /*allow_wild*/, (flags & EW_DIR ? 0:1 ) /*allow directory*/);
Bram Moolenaar206f0112014-03-12 16:51:55 +0100543 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 if (cnt > 0)
545 cnt = vms_match_num;
546 for (i = 0; i < cnt; i++)
547 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100548 if (mch_getperm(vms_fmatch[i]) >= 0) // add existing file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 addfile(gap, vms_fmatch[i], flags);
550 }
551 return cnt;
552}
553
554/*
555 * attempt to translate a mixed unix-vms file specification to pure vms
556 */
557 static void
558vms_unix_mixed_filespec(char *in, char *out)
559{
560 char *lastcolon;
561 char *end_of_dir;
562 char ch;
563 int len;
Bram Moolenaar206f0112014-03-12 16:51:55 +0100564 char *out_str=out;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565
Bram Moolenaar0f873732019-12-05 20:28:46 +0100566 // copy vms filename portion up to last colon
567 // (node and/or disk)
568 lastcolon = strrchr(in, ':'); // find last colon
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000569 if (lastcolon != NULL)
570 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 len = lastcolon - in + 1;
572 strncpy(out, in, len);
573 out += len;
574 in += len;
575 }
576
Bram Moolenaar0f873732019-12-05 20:28:46 +0100577 end_of_dir = NULL; // default: no directory
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578
Bram Moolenaar0f873732019-12-05 20:28:46 +0100579 // start of directory portion
Bram Moolenaar071d4272004-06-13 20:20:40 +0000580 ch = *in;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000581 if ((ch == '[') || (ch == '/') || (ch == '<')) // start of directory(s) ?
582 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583 ch = '[';
584 SKIP_FOLLOWING_SLASHES(in);
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000585 }
586 else if (EQN(in, "../", 3)) // Unix parent directory?
587 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 *out++ = '[';
589 *out++ = '-';
590 end_of_dir = out;
591 ch = '.';
592 in += 2;
593 SKIP_FOLLOWING_SLASHES(in);
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000594 }
595 else
596 { // not a special character
597 while (EQN(in, "./", 2)) // Ignore Unix "current dir"
598 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599 in += 2;
600 SKIP_FOLLOWING_SLASHES(in);
601 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000602 if (strchr(in, '/') == NULL) // any more Unix directories ?
603 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100604 strcpy(out, in); // No - get rest of the spec
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 return;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000606 }
607 else
608 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100609 *out++ = '['; // Yes, denote a Vms subdirectory
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 ch = '.';
611 --in;
612 }
613 }
614
Bram Moolenaar0f873732019-12-05 20:28:46 +0100615 // if we get here, there is a directory part of the filename
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616
Bram Moolenaar0f873732019-12-05 20:28:46 +0100617 // initialize output file spec
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 *out++ = ch;
619 ++in;
620
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000621 while (*in != '\0')
622 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623 ch = *in;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000624 if ((ch == ']') || (ch == '/') || (ch == '>') ) // end of (sub)directory ?
625 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000626 end_of_dir = out;
627 ch = '.';
628 SKIP_FOLLOWING_SLASHES(in);
629 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000630 else if (EQN(in, "../", 3)) // Unix parent directory?
631 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 *out++ = '-';
633 end_of_dir = out;
634 ch = '.';
635 in += 2;
636 SKIP_FOLLOWING_SLASHES(in);
637 }
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000638 else
639 {
640 while (EQN(in, "./", 2)) // Ignore Unix "current dir"
641 {
642 end_of_dir = out;
643 in += 2;
644 SKIP_FOLLOWING_SLASHES(in);
645 ch = *in;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 }
647 }
648
Bram Moolenaar0f873732019-12-05 20:28:46 +0100649 // Place next character into output file spec
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 *out++ = ch;
651 ++in;
652 }
653
Bram Moolenaar0f873732019-12-05 20:28:46 +0100654 *out = '\0'; // Terminate output file spec
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655
Bram Moolenaar0f873732019-12-05 20:28:46 +0100656 if (end_of_dir != NULL) // Terminate directory portion
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657 *end_of_dir = ']';
658}
659
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660/*
661 * for decc$to_vms in vms_fixfilename
662 */
663 static int
664vms_fspec_proc(char *fil, int val)
665{
666 strcpy(Fspec_Rms,fil);
667 return(1);
668}
669
670/*
671 * change unix and mixed filenames to VMS
672 */
673 void *
674vms_fixfilename(void *instring)
675{
676 static char *buf = NULL;
677 static size_t buflen = 0;
678 size_t len;
679
Bram Moolenaar0f873732019-12-05 20:28:46 +0100680 // get a big-enough buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 len = strlen(instring) + 1;
682 if (len > buflen)
683 {
684 buflen = len + 128;
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200685 buf = vim_realloc(buf, buflen * sizeof(char));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686 }
687
688#ifdef DEBUG
Yegappan Lakshmanane89aef32025-05-14 20:31:55 +0200689 char *tmpbuf = NULL;
690 tmpbuf = ALLOC_MULT(char, buflen);
691 strcpy(tmpbuf, instring);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692#endif
693
Bram Moolenaar0f873732019-12-05 20:28:46 +0100694 Fspec_Rms = buf; // for decc$to_vms
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695
Bram Moolenaar9964e462007-05-05 17:54:07 +0000696 if (strchr(instring,'/') == NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100697 // It is already a VMS file spec
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698 strcpy(buf, instring);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100699 else if (strchr(instring,'"') == NULL) // password in the path?
Bram Moolenaar9964e462007-05-05 17:54:07 +0000700 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100701 // Seems it is a regular file, let guess that it is pure Unix fspec
Bram Moolenaar9f1983d2022-05-12 20:35:35 +0100702 if ( (strchr(instring,'[') == NULL) && (strchr(instring,'<') == NULL) &&
Bram Moolenaar82c38fe2021-01-04 10:47:26 +0100703 (strchr(instring,']') == NULL) && (strchr(instring,'>') == NULL) &&
704 (strchr(instring,':') == NULL) )
705 {
706 // It must be a truly unix fspec
707 decc$to_vms(instring, vms_fspec_proc, 0, 0);
708 }
709 else
710 {
711 // It is a mixed fspec
Bram Moolenaar071d4272004-06-13 20:20:40 +0000712 vms_unix_mixed_filespec(instring, buf);
Bram Moolenaar82c38fe2021-01-04 10:47:26 +0100713 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714 }
715 else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100716 // we have a password in the path
717 // decc$ functions can not handle
718 // this is our only hope to resolv
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 vms_unix_mixed_filespec(instring, buf);
720
721 return buf;
722}
Bram Moolenaar9964e462007-05-05 17:54:07 +0000723
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724/*
725 * Remove version number from file name
726 * we need it in some special cases as:
727 * creating swap file name and writing new file
728 */
729 void
730vms_remove_version(void * fname)
731{
732 char_u *cp;
733 char_u *fp;
734
Bram Moolenaar0f873732019-12-05 20:28:46 +0100735 if ((cp = vim_strchr( fname, ';')) != NULL) // remove version
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 *cp = '\0';
737 else if ((cp = vim_strrchr( fname, '.')) != NULL )
738 {
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000739 if ((fp = vim_strrchr( fname, ']')) != NULL )
740 {;}
741 else if ((fp = vim_strrchr( fname, '>')) != NULL )
742 {;}
743 else
744 fp = fname;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745
746 while ( *fp != '\0' && fp < cp )
747 if ( *fp++ == '.' )
748 *cp = '\0';
749 }
750 return ;
751}
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100752
753struct typeahead_st {
754 unsigned short numchars;
755 unsigned char firstchar;
756 unsigned char reserved0;
757 unsigned long reserved1;
758} typeahead;
759
760/*
761 * Wait "msec" msec until a character is available from file descriptor "fd".
762 * "msec" == 0 will check for characters once.
763 * "msec" == -1 will block until a character is available.
764 */
765 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100766RealWaitForChar(
Bram Moolenaar0f873732019-12-05 20:28:46 +0100767 int fd UNUSED, // always read from iochan
Bram Moolenaar05540972016-01-30 20:31:25 +0100768 long msec,
Bram Moolenaarde5e2c22016-11-04 20:35:31 +0100769 int *check_for_gpm UNUSED,
770 int *interrupted)
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100771{
772 int status;
773 struct _generic_64 time_curr;
774 struct _generic_64 time_diff;
775 struct _generic_64 time_out;
776 unsigned int convert_operation = LIB$K_DELTA_SECONDS_F;
Bram Moolenaar206f0112014-03-12 16:51:55 +0100777 float sec =(float) msec/1000;
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100778
Bram Moolenaar0f873732019-12-05 20:28:46 +0100779 // make sure the iochan is set
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100780 if (!iochan)
781 get_tty();
782
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000783 if (sec > 0)
784 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100785 // time-out specified; convert it to absolute time
786 // sec>0 requirement of lib$cvtf_to_internal_time()
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100787
Bram Moolenaar0f873732019-12-05 20:28:46 +0100788 // get current time (number of 100ns ticks since the VMS Epoch)
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100789 status = sys$gettim(&time_curr);
790 if (status != SS$_NORMAL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100791 return 0; // error
792 // construct the delta time
Bram Moolenaar206f0112014-03-12 16:51:55 +0100793#if __G_FLOAT==0
794# ifndef VAX
Bram Moolenaar0f873732019-12-05 20:28:46 +0100795 // IEEE is default on IA64, but can be used on Alpha too - but not on VAX
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100796 status = lib$cvts_to_internal_time(
797 &convert_operation, &sec, &time_diff);
Bram Moolenaar206f0112014-03-12 16:51:55 +0100798# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +0100799#else // default on Alpha and VAX
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100800 status = lib$cvtf_to_internal_time(
Bram Moolenaar206f0112014-03-12 16:51:55 +0100801 &convert_operation, &sec, &time_diff);
802#endif
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100803 if (status != LIB$_NORMAL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100804 return 0; // error
805 // add them up
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100806 status = lib$add_times(
807 &time_curr,
808 &time_diff,
809 &time_out);
810 if (status != LIB$_NORMAL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100811 return 0; // error
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100812 }
813
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000814 while (TRUE)
815 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100816 // select()
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100817 status = sys$qiow(0, iochan, IO$_SENSEMODE | IO$M_TYPEAHDCNT, iosb,
818 0, 0, &typeahead, 8, 0, 0, 0, 0);
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100819 if (status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100820 return 0; // error
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100821
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100822 if (typeahead.numchars)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100823 return 1; // ready to read
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100824
Bram Moolenaar0f873732019-12-05 20:28:46 +0100825 // there's nothing to read; what now?
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000826 if (msec == 0)
827 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100828 // immediate time-out; return impatiently
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100829 return 0;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000830 }
831 else if (msec < 0)
832 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100833 // no time-out; wait on indefinitely
834 return 1; // fakeout to force a wait in vms_read()
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000835 }
836 else
837 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100838 // time-out needs to be checked
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100839 status = sys$gettim(&time_curr);
840 if (status != SS$_NORMAL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100841 return 0; // error
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100842
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100843 status = lib$sub_times(
844 &time_out,
845 &time_curr,
846 &time_diff);
847 if (status != LIB$_NORMAL)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100848 return 0; // error, incl. time_diff < 0 (i.e. time-out)
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100849
Bram Moolenaar0f873732019-12-05 20:28:46 +0100850 // otherwise wait some more
Bram Moolenaar792f0e32018-02-27 17:27:13 +0100851 }
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100852 }
853}