1/* $LP: LPlib/source/LPdir_vms.c,v 1.20 2004/08/26 13:36:05 _cvs_levitte Exp $ */
2/*
3 * Copyright (c) 2004, Richard Levitte <richard@levitte.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <stddef.h>
29#include <stdlib.h>
30#include <string.h>
31#include <errno.h>
32#include <descrip.h>
33#include <namdef.h>
34#include <rmsdef.h>
35#include <libfildef.h>
36#include <lib$routines.h>
37#include <strdef.h>
38#include <str$routines.h>
39#include <stsdef.h>
40#ifndef LPDIR_H
41#include "LPdir.h"
42#endif
43
44/* Because some compiler options hide this macor */
45#ifndef EVMSERR
46#define EVMSERR		65535  /* error for non-translatable VMS errors */
47#endif
48
49struct LP_dir_context_st
50{
51  unsigned long VMS_context;
52#ifdef NAML$C_MAXRSS
53  char filespec[NAML$C_MAXRSS+1];
54  char result[NAML$C_MAXRSS+1];
55#else
56  char filespec[256];
57  char result[256];
58#endif
59  struct dsc$descriptor_d filespec_dsc;
60  struct dsc$descriptor_d result_dsc;
61};
62
63const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
64{
65  int status;
66  char *p, *r;
67  size_t l;
68  unsigned long flags = 0;
69#ifdef NAML$C_MAXRSS
70  flags |= LIB$M_FIL_LONG_NAMES;
71#endif
72
73  if (ctx == NULL || directory == NULL)
74    {
75      errno = EINVAL;
76      return 0;
77    }
78
79  errno = 0;
80  if (*ctx == NULL)
81    {
82      size_t filespeclen = strlen(directory);
83      char *filespec = NULL;
84
85      /* MUST be a VMS directory specification!  Let's estimate if it is. */
86      if (directory[filespeclen-1] != ']'
87	  && directory[filespeclen-1] != '>'
88	  && directory[filespeclen-1] != ':')
89	{
90	  errno = EINVAL;
91	  return 0;
92	}
93
94      filespeclen += 4;		/* "*.*;" */
95
96      if (filespeclen >
97#ifdef NAML$C_MAXRSS
98	  NAML$C_MAXRSS
99#else
100	  255
101#endif
102	  )
103	{
104	  errno = ENAMETOOLONG;
105	  return 0;
106	}
107
108      *ctx = (LP_DIR_CTX *)malloc(sizeof(LP_DIR_CTX));
109      if (*ctx == NULL)
110	{
111	  errno = ENOMEM;
112	  return 0;
113	}
114      memset(*ctx, '\0', sizeof(LP_DIR_CTX));
115
116      strcpy((*ctx)->filespec,directory);
117      strcat((*ctx)->filespec,"*.*;");
118      (*ctx)->filespec_dsc.dsc$w_length = filespeclen;
119      (*ctx)->filespec_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
120      (*ctx)->filespec_dsc.dsc$b_class = DSC$K_CLASS_S;
121      (*ctx)->filespec_dsc.dsc$a_pointer = (*ctx)->filespec;
122      (*ctx)->result_dsc.dsc$w_length = 0;
123      (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
124      (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D;
125      (*ctx)->result_dsc.dsc$a_pointer = 0;
126    }
127
128  (*ctx)->result_dsc.dsc$w_length = 0;
129  (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
130  (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D;
131  (*ctx)->result_dsc.dsc$a_pointer = 0;
132
133  status = lib$find_file(&(*ctx)->filespec_dsc, &(*ctx)->result_dsc,
134			 &(*ctx)->VMS_context, 0, 0, 0, &flags);
135
136  if (status == RMS$_NMF)
137    {
138      errno = 0;
139      vaxc$errno = status;
140      return NULL;
141    }
142
143  if(!$VMS_STATUS_SUCCESS(status))
144    {
145      errno = EVMSERR;
146      vaxc$errno = status;
147      return NULL;
148    }
149
150  /* Quick, cheap and dirty way to discard any device and directory,
151     since we only want file names */
152  l = (*ctx)->result_dsc.dsc$w_length;
153  p = (*ctx)->result_dsc.dsc$a_pointer;
154  r = p;
155  for (; *p; p++)
156    {
157      if (*p == '^' && p[1] != '\0') /* Take care of ODS-5 escapes */
158	{
159	  p++;
160	}
161      else if (*p == ':' || *p == '>' || *p == ']')
162	{
163	  l -= p + 1 - r;
164	  r = p + 1;
165	}
166      else if (*p == ';')
167	{
168	  l = p - r;
169	  break;
170	}
171    }
172
173  strncpy((*ctx)->result, r, l);
174  (*ctx)->result[l] = '\0';
175  str$free1_dx(&(*ctx)->result_dsc);
176
177  return (*ctx)->result;
178}
179
180int LP_find_file_end(LP_DIR_CTX **ctx)
181{
182  if (ctx != NULL && *ctx != NULL)
183    {
184      int status = lib$find_file_end(&(*ctx)->VMS_context);
185
186      free(*ctx);
187
188      if(!$VMS_STATUS_SUCCESS(status))
189	{
190	  errno = EVMSERR;
191	  vaxc$errno = status;
192	  return 0;
193	}
194      return 1;
195    }
196  errno = EINVAL;
197  return 0;
198}
199
200