Logo Search packages:      
Sourcecode: nedit version File versions  Download package

vmsUtils.c

static const char CVSID[] = "$Id: vmsUtils.c,v 1.6 2004/07/21 11:32:07 yooden Exp $";
/*******************************************************************************
*                                                            *
* vmsUtils.c - Utility routines for VMS systems.                         *
*                                                            *
*            This file contains the following functions:                 *
*                                                            *
*      StrDescToNul      - Convert VMS String Descriptor to C-like null-     *
*                        terminated string.  Returns the address of      *
*                        the malloc'd string.  (Call FreeNulStr() when   *
*                        done with the string.)                    *
*      NulStrToDesc        - Convert C-like null-terminated string to VMS      *
*                        String Descriptor.  Returns the address of      *
*                        the malloc'd descriptor, which should be free'd *
*                        when done by calling FreeStrDesc().             *
*      NulStrWrtDesc       - Convert C-like null-terminated string to VMS      *
*                        String Descriptor for writing into.  The C      *
*                        String should already be allocated and the      *
*                        length passed as the second parameter.  Returns *
*                        the address of the malloc'd descriptor, which   *
*                        should be free'd when done via FreeStrDesc().   *
*      FreeNulStr    - Frees null-terminated strings created by          *
*                        StrDescToNul().                           *
*      FreeStrDesc         - Frees VMS String Descriptors created by           *
*                        NulStrToDesc() and NulStrWrtDesc().             *
*      ConvertVMSCommandLine  - Convert an argument vector representing a    *
*                        VMS-style command line to something Unix-like.  *
*                        Limitations: no abbreviations, some syntax      *
*                        information is lost so some errors will yield   *
*                        strange results.                          * 
*                                                            *
*      rint          - Returns the integer (represented as a double      *
*                        precision number) nearest its double argument.  *
*                                                            *
*      VMSFileScan         - Calls LIB$FILE_SCAN for filenames on VMS systems  *
*                                                            *
*      VMSFileScanDone   - Ends LIB$FILE_SCAN context & frees memory used    *
*                                                                              *
*        ProcAlive         - See if a process (identified by pID) is still     *
*                        alive on VMS.                             *
*                                                            *
* Copyright (C) 1999 Mark Edel                                           *
*                                                            *
* This is free software; you can redistribute it and/or modify it under the    *
* terms of the GNU General Public License as published by the Free Software    *
* Foundation; either version 2 of the License, or (at your option) any later   *
* version. In addition, you may distribute version of this program linked to   *
* Motif or Open Motif. See README for details.                                 *
*                                                                              *
* This software is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        *
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License        *
* for more details.                                                *
*                                                            *
* You should have received a copy of the GNU General Public License along with *
* software; if not, write to the Free Software Foundation, Inc., 59 Temple     *
* Place, Suite 330, Boston, MA  02111-1307 USA                               *
*                                                            *
* Nirvana Text Editor                                              *
* February 22, 1993                                                *
*                                                            *
* Written by Joy Kyriakopulos                                      *
*                                                            *
*******************************************************************************/

#ifdef VMS

#include stdio
#include string
#include stdlib
#include ctype
#include errno
#include math
#include unixio
#include fab
#include nam
#include rmsdef
#include ssdef
#include starlet
#include lib$routines
#include jpidef
#include descrip
#include "vmsUtils.h"

/* Maximum number and length of arguments for ConvertVMSCommandLine */
#define MAX_ARGS 100
#define MAX_CMD_LENGTH 256
/* Maximum number of files handled by VMSFileScan */
#define MAX_NUM_FILES 100

static void successRtn(struct FAB *dirFab);     /* VMSFileScan */
static void errRtn(struct FAB *dirFab);         /* VMSFileScan */

static void addArgChar(int *argc, char *argv[], char c);

char *StrDescToNul(struct dsc$descriptor_s *vmsString)
{
    char *str;
    
    if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class !=
          DSC$K_CLASS_S)
      fprintf(stderr,"Warning from StrDescToNul: descriptor class/type = %d/%d\n%s",
          vmsString->dsc$b_class, vmsString->dsc$b_dtype,
          "               Expecting 1/14\n");
    str = malloc(vmsString->dsc$w_length + 1);
    strncpy(str, vmsString->dsc$a_pointer, vmsString->dsc$w_length);
    str[vmsString->dsc$w_length + 1] = '\0';
    return str;
}

struct dsc$descriptor_s *NulStrToDesc(char *nulTString)
{
    struct dsc$descriptor_s *vmsString;
    int strLen;
    char *tmp;
    
    strLen = strlen(nulTString);
    if (strLen > 32767)
      fprintf(stderr,"Warning from NulStrToDesc: string > 32767 bytes\n");
    vmsString = malloc(sizeof(struct dsc$descriptor_s) + strLen + 1);
    vmsString->dsc$a_pointer = ((char *)vmsString) 
                        + sizeof(struct dsc$descriptor_s);
    tmp = strcpy(vmsString->dsc$a_pointer, nulTString);
    vmsString->dsc$w_length = strLen;
    vmsString->dsc$b_dtype = DSC$K_DTYPE_T;
    vmsString->dsc$b_class = DSC$K_CLASS_S;
    return vmsString;
}

struct dsc$descriptor_s *NulStrWrtDesc(char *nulTString, int strLen)
{
    struct dsc$descriptor_s *vmsString;
    
    if (strLen > 32767)
      fprintf(stderr,"Warning from NulStrToDesc: string > 32767 bytes\n");
    memset(nulTString, 0, strLen);
    /*bzero(nulTString, strLen);*/
    vmsString = malloc(sizeof(struct dsc$descriptor_s));
    vmsString->dsc$a_pointer = nulTString;
    vmsString->dsc$w_length = strLen;
    vmsString->dsc$b_dtype = DSC$K_DTYPE_T;
    vmsString->dsc$b_class = DSC$K_CLASS_S;
    return vmsString;
}

void FreeNulStr(char *nulTString)
{
    free(nulTString);
}

void FreeStrDesc(struct dsc$descriptor_s *vmsString)
{
    if (vmsString->dsc$b_dtype != DSC$K_DTYPE_T || vmsString->dsc$b_class !=
          DSC$K_CLASS_S)
      fprintf(stderr,"Warning from FreeStrDesc: descriptor class/type = %d/%d\n%s",
          vmsString->dsc$b_class, vmsString->dsc$b_dtype,
          "               Expecting 1/14\n");
    free(vmsString);
}

#if !(defined __ALPHA && (defined _XOPEN_SOURCE_EXTENDED || !defined _ANSI_C_SOURCE))
double rint(double dnum)
{
    return floor(dnum + 0.5);
}
#endif

/*
** Re-read the command line and convert it from VMS style to unix style.
** Replaces argv and argc with Unix-correct versions.  This is
** a poor solution to parsing VMS command lines because some information
** is lost and some elements of the syntax are not checked.  Users also
** can't abbreviate qualifiers as is customary under VMS.
*/
void ConvertVMSCommandLine(int *argc, char **argv[])
{
    int i;
    short cmdLineLen;
    char *c, cmdLine[MAX_CMD_LENGTH], *oldArg0;
    struct dsc$descriptor_s *cmdLineDesc;

    /* get the command line (don't use the old argv and argc because VMS
       has removed the quotes and altered the line somewhat */
    cmdLineDesc = NulStrWrtDesc(cmdLine, MAX_CMD_LENGTH);
    lib$get_foreign(cmdLineDesc, 0, &cmdLineLen, 0);
    FreeStrDesc(cmdLineDesc);
    
    /* begin a new argv and argc, but preserve the original argv[0]
       which is not returned by lib$get_foreign */
    oldArg0 = (*argv)[0];
    *argv = (char **)malloc(sizeof(char *) * MAX_ARGS);
    (*argv)[0] = oldArg0;
    *argc = 1;

    /* scan all of the text on the command line, reconstructing the arg list */
    for (i=0, c=cmdLine; i<cmdLineLen; c++, i++) {
      if (*c == '\t') {
          addArgChar(argc, *argv, ' ');
      } else if (*c == '/') {
          addArgChar(argc, *argv, ' ');
          addArgChar(argc, *argv, '-');
      } else if (*c == '=') {
          addArgChar(argc, *argv, ' ');
      } else if (*c == ',') {
          addArgChar(argc, *argv, ' ');
      } else {
          addArgChar(argc, *argv, *c);
      }
    }
    addArgChar(argc, *argv, ' ');
}

/*
** Accumulate characters in an argv argc style argument list.  Spaces
** mean start a new argument and extra ones are ignored.  Argument strings
** are accumulated internally in the routine and not flushed into argv
** until a space is recieved (so a final space is needed to finish argv).
*/
static void addArgChar(int *argc, char *argv[], char c)
{
    static char str[MAX_CMD_LENGTH];
    static char *strPtr = str;
    static int inQuoted = FALSE, preserveQuotes = FALSE;
    int strLen;

    if (c == ' ') {
      if (strPtr == str) {    /* don't form empty arguments */
          return;
      } else if (inQuoted) {  /* preserve spaces inside of quoted strings */
          *strPtr++ = c;
      } else {          /* flush the accumulating argument */
          strLen = strPtr - str;
          argv[*argc] = (char *)malloc(sizeof(char) * (strLen + 1));
          strncpy(argv[*argc], str, strLen);
          argv[*argc][strLen] = '\0';
          (*argc)++;
          strPtr = str;
          inQuoted = FALSE;
      }
    } else if (c == '"') {    /* note when quoted strings begin and end */
      if (inQuoted) {
          inQuoted = FALSE;
      } else {
          preserveQuotes = (strPtr != str);     /* remove quotes around the  */
          inQuoted = TRUE;                /* outsides of arguments but */
      }                             /* preserve internal ones so */
      if (preserveQuotes)                 /* access strings will work  */
          *strPtr++ = c;
    } else if (inQuoted) {
      *strPtr++ = c;
    } else {
      *strPtr++ = tolower(c);
    }
}
      
/*
 * VMSFileScan -- Routine to call LIB$FILE_SCAN for filenames on VMS systems 
 *
 *    Returns: integer value >= 0, the number of files returned in namelist
 *                       = -1, an error was returned from LIB$FILE_SCAN
 *                            and the error is printed on stderr
 *
 *    Parameters:
 *
 *        dirname:  input file specification (can include wildcards)
 *        namelist: array of pointers to the expanded file specs
 *                   (free each string and the table of pointers when done)
 *        select:   user supplied function (or NULL) to call to select
 *                   which filenames are to be included in dirname array.
 *                   If NULL, all filenames will be included.
 *        fnf:      specify INCLUDE_FNF, EXCLUDE_FNF, or NOT_ERR_FNF 
 *                 INCLUDE_FNF: the resultant file specification is 
 *                      passed on to select() routine for returning
 *                      in namelist, even though the file doesn't exist
 *                 EXCLUDE_FNF: return -1 (error) if dirname doesn't exist
 *                 NOT_ERR_FNF: return 0 (no error) if no files found
 *
 *    Call VMSFileScanDone() to free memory used by the FAB and RAB and clear
 *    sticky filename defaults for another scanning sequence.
 */
static char **Namelist;
static int NumFilesFound;
static int Fnf;
static int Context = 0;
static int (*SelectRoutine)();            /* saves select fcn for successRtn    */
static struct FAB *DirFAB = NULL;
static struct NAM *DirNAM = NULL;

int VMSFileScan(char *dirname, char *(*namelist[]), int (*select)(), int fnf)
{
    char result_name[NAM$C_MAXRSS+1];     /* array for resulting file spec      */
    char expanded_name[NAM$C_MAXRSS+1];   /* array for expanded file spec           */
    int stat;

    if (DirFAB == NULL) {
      DirFAB = (struct FAB *) malloc(sizeof(struct FAB));
      DirNAM = (struct NAM *) malloc(sizeof(struct NAM));
      *DirFAB = cc$rms_fab;         /* initialize FAB with default values */
      *DirNAM = cc$rms_nam;         /*     "      NAMe block "  "   "     */
      DirFAB->fab$l_nam = DirNAM;   /* point FAB to NAM block           */
      DirFAB->fab$l_dna = "*.";     /* default is no extension            */
      DirFAB->fab$b_dns = 2;
      DirNAM->nam$b_ess = sizeof(expanded_name) - 1;
        DirNAM->nam$b_rss = sizeof(result_name) - 1;
    }

    DirFAB->fab$l_fna = dirname;    /* wildcard spec for LIB$FILE_SCAN    */
    DirFAB->fab$b_fns = strlen(dirname);
    DirNAM->nam$l_esa = &expanded_name[0]; /* expanded file specs ret'nd here */
    DirNAM->nam$l_rsa = &result_name[0];   /* resultant file specs ret'nd here */
    SelectRoutine = select;
    NumFilesFound = 0;
    Fnf = fnf;
    Namelist = malloc(sizeof(char *) * MAX_NUM_FILES);
    *namelist = 0;
    stat = lib$file_scan(DirFAB, successRtn, errRtn, &Context); 

    if (stat != RMS$_NORMAL && stat != RMS$_FNF && stat != RMS$_NMF) {
      fprintf(stderr, "Error calling LIB$FILE_SCAN: %s\n",
            strerror(EVMSERR, stat));
      return -1;
    }
    if (stat == RMS$_FNF && Fnf == EXCLUDE_FNF)
      return -1;
    *namelist = Namelist;
    return NumFilesFound;
}

static void successRtn(struct FAB *dirFab)
{
    if (NumFilesFound >= MAX_NUM_FILES)
      return;

    /* terminate filename string with a null to pass to user's select routine */
    dirFab->fab$l_nam->nam$l_rsa[dirFab->fab$l_nam->nam$b_rsl] = '\0';

    /* if user's select routine returns value != 0, then put into name list */
    if (SelectRoutine == NULL || 
            (*SelectRoutine)(dirFab->fab$l_nam->nam$l_rsa)) {
      ++NumFilesFound;
      Namelist[NumFilesFound-1] = malloc(dirFab->fab$l_nam->nam$b_rsl+1);
      strcpy(Namelist[NumFilesFound-1], dirFab->fab$l_nam->nam$l_rsa);
      /* printf("File: %s included\n", dirFab->fab$l_nam->nam$l_rsa); */
      
    }
}

static void errRtn(struct FAB *dirFab)
{
    if (dirFab->fab$l_sts == RMS$_FNF && Fnf == INCLUDE_FNF)
      successRtn(dirFab);        /* return filename even tho' doesn't exist */
    else if (dirFab->fab$l_sts != RMS$_FNF || (dirFab->fab$l_sts == RMS$_FNF
            && Fnf != NOT_ERR_FNF))
      fprintf(stderr, "Error - %s:  %s\n", strerror(EVMSERR,
             dirFab->fab$l_sts), dirFab->fab$l_fna);
}

void VMSFileScanDone(void)
{
    if (DirFAB != NULL) {
      int s;
      if ((s=lib$file_scan_end(DirFAB, &Context)) != RMS$_NORMAL 
                  && s != SS$_NORMAL)
          fprintf(stderr, "Error calling LIB$FILE_SCAN_END: %s\n",
                  strerror(EVMSERR,s));
      free(DirNAM);
      DirNAM = NULL;
      free(DirFAB);
      DirFAB = NULL;
    }
}

/*
 * ProcAlive: see if a process (identified by pID) is still alive on VMS.
 *
 *    Returns:  1 - process exists
 *            0 - process does not exist
 *           -1 - error getting process info
 */
int ProcAlive(const unsigned int pID)
{
    int jpiStat;
    short retLen;
    char userName[13];              /* 12 plus 1 for ending null */
    struct getJPIdescriptor {
      short bufLength;
      short itemCode;
      char  *bufAddr;
      short *retLenAddr;
      int   *endList;
    } getJPID;

    getJPID.bufLength  = 12;        /* (max) size of user name */
    getJPID.itemCode   = JPI$_USERNAME;
    getJPID.bufAddr    = userName;
    getJPID.retLenAddr = &retLen;
    getJPID.endList    = 0;
    jpiStat = sys$getjpiw(1,&pID,0,&getJPID,0,0,0);
    /* printf("in ProcAlive - jpiStat = %d, pid = %X\n", jpiStat, pID); */
    if (jpiStat == SS$_NORMAL || jpiStat == SS$_NOPRIV 
            || jpiStat == SS$_SUSPENDED)
      return 1;               /* process exists   */
    if (jpiStat == SS$_NONEXPR)
      return 0;               /* process does not exist */
    fprintf(stderr, "Error calling GETJPI in ProcAlive.  Status = %d\n",
          jpiStat);
    return -1;                      /* error            */
}


#endif /*VMS*/

Generated by  Doxygen 1.6.0   Back to index