diff options
author | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2004-06-13 20:20:40 +0000 |
commit | 071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch) | |
tree | 221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/os_vms.c | |
parent | b4210b3bc14e2918f153a7307530fbe6eba659e1 (diff) | |
download | vim-071d4279d6ab81b7187b48f3a0fc61e587b6db6c.zip |
updated for version 7.0001
Diffstat (limited to 'src/os_vms.c')
-rw-r--r-- | src/os_vms.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/src/os_vms.c b/src/os_vms.c new file mode 100644 index 000000000..ab5eca4e1 --- /dev/null +++ b/src/os_vms.c @@ -0,0 +1,657 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * VMS port by Henk Elbers + * VMS deport by Zoltan Arpadffy + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +#include "vim.h" + +typedef struct +{ + char class; + char type; + short width; + union + { + struct + { + char _basic[3]; + char length; + } y; + int basic; + } x; + int extended; +} TT_MODE; + +typedef struct +{ + short buflen; + short itemcode; + char *bufadrs; + int *retlen; +} ITEM; + +typedef struct +{ + ITEM equ; + int nul; +} ITMLST1; + +typedef struct +{ + ITEM index; + ITEM string; + int nul; +} ITMLST2; + +static TT_MODE orgmode; +static short iochan; /* TTY I/O channel */ +static short iosb[4]; /* IO status block */ + +static int vms_match_num = 0; +static int vms_match_free = 0; +static char_u **vms_fmatch = NULL; +static char *Fspec_Rms; /* rms file spec, passed implicitly between routines */ + + + +static TT_MODE get_tty __ARGS((void)); +static void set_tty __ARGS((int row, int col)); + +#define EXPL_ALLOC_INC 64 + +#define EQN(S1,S2,LN) (strncmp(S1,S2,LN) == 0) +#define SKIP_FOLLOWING_SLASHES(Str) while (Str[1] == '/') ++Str + + +/* + * vul_desc vult een descriptor met een string en de lengte + * hier van. + */ + static void +vul_desc(DESC *des, char *str) +{ + des->dsc$b_dtype = DSC$K_DTYPE_T; + des->dsc$b_class = DSC$K_CLASS_S; + des->dsc$a_pointer = str; + des->dsc$w_length = str ? strlen(str) : 0; +} + +/* + * vul_item vult een item met een aantal waarden + */ + static void +vul_item(ITEM *itm, short len, short cod, char *adr, int *ret) +{ + itm->buflen = len; + itm->itemcode = cod; + itm->bufadrs = adr; + itm->retlen = ret; +} + + void +mch_settmode(int tmode) +{ + int status; + + if ( tmode == TMODE_RAW ) + set_tty(0, 0); + else{ + switch (orgmode.width) + { + case 132: OUT_STR_NF((char_u *)"\033[?3h\033>"); break; + case 80: OUT_STR_NF((char_u *)"\033[?3l\033>"); break; + default: break; + } + out_flush(); + status = sys$qiow(0, iochan, IO$_SETMODE, iosb, 0, 0, + &orgmode, sizeof(TT_MODE), 0,0,0,0); + if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) + return; + (void)sys$dassgn(iochan); + iochan = 0; + } +} + + static void +set_tty(int row, int col) +{ + int status; + TT_MODE newmode; /* New TTY mode bits */ + static short first_time = TRUE; + + if (first_time) + { + orgmode = get_tty(); + first_time = FALSE; + } + newmode = get_tty(); + if (col) + newmode.width = col; + if (row) + newmode.x.y.length = row; + newmode.x.basic |= (TT$M_NOECHO | TT$M_HOSTSYNC); + newmode.x.basic &= ~TT$M_TTSYNC; + newmode.extended |= TT2$M_PASTHRU; + status = sys$qiow(0, iochan, IO$_SETMODE, iosb, 0, 0, + &newmode, sizeof(newmode), 0, 0, 0, 0); + if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) + return; +} + + static TT_MODE +get_tty(void) +{ + + static $DESCRIPTOR(odsc,"SYS$OUTPUT"); /* output descriptor */ + + int status; + TT_MODE tt_mode; + + if (!iochan) + status = sys$assign(&odsc,&iochan,0,0); + + status = sys$qiow(0, iochan, IO$_SENSEMODE, iosb, 0, 0, + &tt_mode, sizeof(tt_mode), 0, 0, 0, 0); + if (status != SS$_NORMAL || (iosb[0] & 0xFFFF) != SS$_NORMAL) + { + tt_mode.width = 0; + tt_mode.type = 0; + tt_mode.class = 0; + tt_mode.x.basic = 0; + tt_mode.x.y.length = 0; + tt_mode.extended = 0; + } + return(tt_mode); +} + +/* + * Get the current window size in Rows and Columns. + */ + int +mch_get_shellsize(void) +{ + TT_MODE tmode; + + tmode = get_tty(); /* get size from VMS */ + Columns = tmode.width; + Rows = tmode.x.y.length; + return OK; +} + +/* + * Try to set the window size to Rows and new_Columns. + */ + void +mch_set_shellsize(void) +{ + set_tty(Rows, Columns); + switch (Columns) + { + case 132: OUT_STR_NF((char_u *)"\033[?3h\033>"); break; + case 80: OUT_STR_NF((char_u *)"\033[?3l\033>"); break; + default: break; + } + out_flush(); + screen_start(); +} + + char_u * +mch_getenv(char_u *lognam) +{ + DESC d_file_dev, d_lognam ; + static char buffer[LNM$C_NAMLENGTH+1]; + char_u *cp = NULL; + unsigned long attrib; + int lengte = 0, dum = 0, idx = 0; + ITMLST2 itmlst; + char *sbuf = NULL; + + vul_desc(&d_lognam, (char *)lognam); + vul_desc(&d_file_dev, "LNM$FILE_DEV"); + attrib = LNM$M_CASE_BLIND; + vul_item(&itmlst.index, sizeof(int), LNM$_INDEX, (char *)&idx, &dum); + vul_item(&itmlst.string, LNM$C_NAMLENGTH, LNM$_STRING, buffer, &lengte); + itmlst.nul = 0; + if (sys$trnlnm(&attrib, &d_file_dev, &d_lognam, NULL,&itmlst) == SS$_NORMAL) + { + buffer[lengte] = '\0'; + if (cp = (char_u *)alloc((unsigned)(lengte+1))) + strcpy((char *)cp, buffer); + return(cp); + } + else if ((sbuf = getenv((char *)lognam))) + { + lengte = strlen(sbuf) + 1; + cp = (char_u *)malloc((size_t)lengte); + if (cp) + strcpy((char *)cp, sbuf); + return cp; + } + else + return(NULL); +} + +/* + * mch_setenv VMS version of setenv() + */ + int +mch_setenv(char *var, char *value, int x) +{ + int res, dum; + long attrib = 0L; + char acmode = PSL$C_SUPER; /* needs SYSNAM privilege */ + DESC tabnam, lognam; + ITMLST1 itmlst; + + vul_desc(&tabnam, "LNM$JOB"); + vul_desc(&lognam, var); + vul_item(&itmlst.equ, value ? strlen(value) : 0, value ? LNM$_STRING : 0, + value, &dum); + itmlst.nul = 0; + res = sys$crelnm(&attrib, &tabnam, &lognam, &acmode, &itmlst); + return((res == 1) ? 0 : -1); +} + + int +vms_sys(char *cmd, char *out, char *inp) +{ + DESC cdsc, odsc, idsc; + long status; + + if (cmd) + vul_desc(&cdsc, cmd); + if (out) + vul_desc(&odsc, out); + if (inp) + vul_desc(&idsc, inp); + + lib$spawn(cmd ? &cdsc : NULL, /* command string */ + inp ? &idsc : NULL, /* input file */ + out ? &odsc : NULL, /* output file */ + 0, 0, 0, &status, 0, 0, 0, 0, 0, 0); + return status; +} + +/* + * Convert VMS system() or lib$spawn() return code to Unix-like exit value. + */ + int +vms_sys_status(int status) +{ + if (status != SS$_NORMAL && (status & STS$M_SUCCESS) == 0) + return status; /* Command failed. */ + return 0; +} + +/* + * vms_read() + * function for low level char input + * + * Returns: input length + */ + int +vms_read(char *inbuf, size_t nbytes) +{ + int status, function, len; + TT_MODE tt_mode; + ITEM itmlst[2]; + static long trm_mask[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; + + /* whatever happened earlier we need an iochan here */ + if (!iochan) + tt_mode = get_tty(); + + vul_item(&itmlst[0], 0, TRM$_MODIFIERS, + (char *)(TRM$M_TM_ESCAPE | TRM$M_TM_NOECHO | TRM$M_TM_NOEDIT | + TRM$M_TM_NOFILTR | TRM$M_TM_NORECALL | TRM$M_TM_TRMNOECHO), 0); + vul_item(&itmlst[1], sizeof(trm_mask), TRM$_TERM, (char *)&trm_mask, 0); + + function = (IO$_READLBLK | IO$M_EXTEND); + memset(inbuf, 0, nbytes); + + while (1) + { + status = sys$qiow(0, iochan, function, &iosb, 0, 0, inbuf, nbytes - 1, + 0, 0, &itmlst, sizeof(itmlst)); + len = strlen(inbuf); + if (len > 0) + break; + } + return len; +} + +/* + * vms_wproc() is called for each matching filename by decc$to_vms(). + * We want to save each match for later retrieval. + * + * Returns: 1 - continue finding matches + * 0 - stop trying to find any further mathces + */ + static int +vms_wproc(char *name, int val) +{ + int i; + int nlen; + static int vms_match_alloced = 0; + + if (val != DECC$K_FILE) /* Directories and foreing non VMS files are not counting */ + return 1; + + if (vms_match_num == 0) { + /* first time through, setup some things */ + if (NULL == vms_fmatch) { + vms_fmatch = (char_u **)alloc(EXPL_ALLOC_INC * sizeof(char *)); + if (!vms_fmatch) + return 0; + vms_match_alloced = EXPL_ALLOC_INC; + vms_match_free = EXPL_ALLOC_INC; + } + else { + /* re-use existing space */ + vms_match_free = vms_match_alloced; + } + } + + vms_remove_version(name); + + /* convert filename to lowercase */ + nlen = strlen(name); + for (i = 0; i < nlen; i++) + name[i] = TOLOWER_ASC(name[i]); + + /* if name already exists, don't add it */ + for (i = 0; i<vms_match_num; i++) { + if (0 == STRCMP((char_u *)name,vms_fmatch[i])) + return 1; + } + if (--vms_match_free == 0) { + /* add more space to store matches */ + vms_match_alloced += EXPL_ALLOC_INC; + vms_fmatch = (char_u **)realloc(vms_fmatch, + sizeof(char **) * vms_match_alloced); + if (!vms_fmatch) + return 0; + vms_match_free = EXPL_ALLOC_INC; + } + vms_fmatch[vms_match_num] = vim_strsave((char_u *)name); + + ++vms_match_num; + return 1; +} + +/* + * mch_expand_wildcards this code does wild-card pattern + * matching NOT using the shell + * + * return OK for success, FAIL for error (you may loose some + * memory) and put an error message in *file. + * + * num_pat number of input patterns + * pat array of pointers to input patterns + * num_file pointer to number of matched file names + * file pointer to array of pointers to matched file names + * + */ + int +mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags) +{ + int i, j = 0, cnt = 0; + char *cp; + char_u buf[MAXPATHL]; + int dir; + int files_alloced, files_free; + + *num_file = 0; /* default: no files found */ + files_alloced = EXPL_ALLOC_INC; + files_free = EXPL_ALLOC_INC; + *file = (char_u **) alloc(sizeof(char_u **) * files_alloced); + if (*file == NULL) + { + *num_file = 0; + return FAIL; + } + for (i = 0; i < num_pat; i++) + { + /* expand environment var or home dir */ + if (vim_strchr(pat[i],'$') || vim_strchr(pat[i],'~')) + expand_env(pat[i],buf,MAXPATHL); + else + STRCPY(buf,pat[i]); + + vms_match_num = 0; /* reset collection counter */ + cnt = decc$to_vms(decc$translate_vms(vms_fixfilename(buf)), vms_wproc, 1, 0); + /* allow wild, no dir */ + if (cnt > 0) + cnt = vms_match_num; + + if (cnt < 1) + continue; + + for (i = 0; i < cnt; i++) + { + /* files should exist if expanding interactively */ + if (!(flags & EW_NOTFOUND) && mch_getperm(vms_fmatch[i]) < 0) + continue; + /* do not include directories */ + dir = (mch_isdir(vms_fmatch[i])); + if (( dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE))) + continue; + /* allocate memory for pointers */ + if (--files_free < 1) + { + files_alloced += EXPL_ALLOC_INC; + *file = (char_u **)realloc(*file, + sizeof(char_u **) * files_alloced); + if (*file == NULL) + { + *file = (char_u **)""; + *num_file = 0; + return(FAIL); + } + files_free = EXPL_ALLOC_INC; + } + + (*file)[*num_file++] = vms_fmatch[i]; + } + } + return OK; +} + + int +mch_expandpath(garray_T *gap, char_u *path, int flags) +{ + int i,cnt = 0; + char *cp; + vms_match_num = 0; + + cnt = decc$to_vms(decc$translate_vms(vms_fixfilename(path)), vms_wproc, 1, 0); + /* allow wild, no dir */ + if (cnt > 0) + cnt = vms_match_num; + for (i = 0; i < cnt; i++) + { + if (mch_getperm(vms_fmatch[i]) >= 0) /* add existing file */ + addfile(gap, vms_fmatch[i], flags); + } + return cnt; +} + +/* + * attempt to translate a mixed unix-vms file specification to pure vms + */ + static void +vms_unix_mixed_filespec(char *in, char *out) +{ + char *lastcolon; + char *end_of_dir; + char ch; + int len; + + /* copy vms filename portion up to last colon + * (node and/or disk) + */ + lastcolon = strrchr(in, ':'); /* find last colon */ + if (lastcolon != NULL) { + len = lastcolon - in + 1; + strncpy(out, in, len); + out += len; + in += len; + } + + end_of_dir = NULL; /* default: no directory */ + + /* start of directory portion */ + ch = *in; + if ((ch == '[') || (ch == '/') || (ch == '<') ) { /* start of directory(s) ? */ + ch = '['; + SKIP_FOLLOWING_SLASHES(in); + } else if (EQN(in, "../", 3)) { /* Unix parent directory? */ + *out++ = '['; + *out++ = '-'; + end_of_dir = out; + ch = '.'; + in += 2; + SKIP_FOLLOWING_SLASHES(in); + } else { /* not a special character */ + while (EQN(in, "./", 2)) { /* Ignore Unix "current dir" */ + in += 2; + SKIP_FOLLOWING_SLASHES(in); + } + if (strchr(in, '/') == NULL) { /* any more Unix directories ? */ + strcpy(out, in); /* No - get rest of the spec */ + return; + } else { + *out++ = '['; /* Yes, denote a Vms subdirectory */ + ch = '.'; + --in; + } + } + + /* if we get here, there is a directory part of the filename */ + + /* initialize output file spec */ + *out++ = ch; + ++in; + + while (*in != '\0') { + ch = *in; + if ((ch == ']') || (ch == '/') || (ch == '>') ) { /* end of (sub)directory ? */ + end_of_dir = out; + ch = '.'; + SKIP_FOLLOWING_SLASHES(in); + } + else if (EQN(in, "../", 3)) { /* Unix parent directory? */ + *out++ = '-'; + end_of_dir = out; + ch = '.'; + in += 2; + SKIP_FOLLOWING_SLASHES(in); + } + else { + while (EQN(in, "./", 2)) { /* Ignore Unix "current dir" */ + end_of_dir = out; + in += 2; + SKIP_FOLLOWING_SLASHES(in); + ch = *in; + } + } + + /* Place next character into output file spec */ + *out++ = ch; + ++in; + } + + *out = '\0'; /* Terminate output file spec */ + + if (end_of_dir != NULL) /* Terminate directory portion */ + *end_of_dir = ']'; +} + + +/* + * for decc$to_vms in vms_fixfilename + */ + static int +vms_fspec_proc(char *fil, int val) +{ + strcpy(Fspec_Rms,fil); + return(1); +} + +/* + * change unix and mixed filenames to VMS + */ + void * +vms_fixfilename(void *instring) +{ + static char *buf = NULL; + static size_t buflen = 0; + size_t len; + + /* get a big-enough buffer */ + len = strlen(instring) + 1; + if (len > buflen) + { + buflen = len + 128; + if (buf) + buf = (char *)realloc(buf, buflen); + else + buf = (char *)calloc(buflen, sizeof(char)); + } + +#ifdef DEBUG + char *tmpbuf = NULL; + tmpbuf = (char *)calloc(buflen, sizeof(char)); + strcpy(tmpbuf, instring); +#endif + + Fspec_Rms = buf; /* for decc$to_vms */ + + if ( strchr(instring,'/') == NULL ) + /* It is already a VMS file spec */ + strcpy(buf, instring); + else if ( strchr(instring,'"') == NULL ){ /* password in the path ? */ + /* Seems it is a regular file, let guess that it is pure Unix fspec */ + if ( decc$to_vms(instring, vms_fspec_proc, 0, 0) <= 0 ) + /* No... it must be mixed */ + vms_unix_mixed_filespec(instring, buf); + } + else + /* we have a password in the path */ + /* decc$ functions can not handle */ + /* this is our only hope to resolv */ + vms_unix_mixed_filespec(instring, buf); + + return buf; +} +/* + * Remove version number from file name + * we need it in some special cases as: + * creating swap file name and writing new file + */ + void +vms_remove_version(void * fname) +{ + char_u *cp; + char_u *fp; + + if ((cp = vim_strchr( fname, ';')) != NULL) /* remove version */ + *cp = '\0'; + else if ((cp = vim_strrchr( fname, '.')) != NULL ) + { + if ((fp = vim_strrchr( fname, ']')) != NULL ) {;} + else if ((fp = vim_strrchr( fname, '>')) != NULL ) {;} + else fp = fname; + + while ( *fp != '\0' && fp < cp ) + if ( *fp++ == '.' ) + *cp = '\0'; + } + return ; +} |