Copy a few files from LPlib (a new project of mine), add a wrapper.
[openssl.git] / crypto / LPdir_vms.c
1 /* $LP: LPlib/source/LPdir_vms.c,v 1.17 2004/06/30 11:36:43 _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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * 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 struct LP_dir_context_st
45 {
46   unsigned long VMS_context;
47 #ifdef NAML$C_MAXRSS
48   char filespec[NAML$C_MAXRSS+1];
49   char result[NAML$C_MAXRSS+1];
50 #else
51   char filespec[256];
52   char result[256];
53 #endif
54   struct dsc$descriptor_d filespec_dsc;
55   struct dsc$descriptor_d result_dsc;
56 };
57
58 const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
59 {
60   int status;
61   char *p, *r;
62   size_t l;
63   const unsigned long flags = 0;
64 #ifdef NAML$C_MAXRSS
65   flags |= LIB$M_FIL_LONG_NAMES;
66 #endif
67
68   if (ctx == NULL || directory == NULL)
69     {
70       errno = EINVAL;
71       return 0;
72     }
73
74   errno = 0;
75   if (*ctx == NULL)
76     {
77       size_t filespeclen = strlen(directory);
78       char *filespec = NULL;
79
80       /* MUST be a VMS directory specification!  Let's estimate if it is. */
81       if (directory[filespeclen-1] != ']'
82           && directory[filespeclen-1] != '>'
83           && directory[filespeclen-1] != ':')
84         {
85           errno = EINVAL;
86           return 0;
87         }
88
89       filespeclen += 4;         /* "*.*;" */
90
91       if (filespeclen >
92 #ifdef NAML$C_MAXRSS
93           NAML$C_MAXRSS
94 #else
95           255
96 #endif
97           )
98         {
99           errno = ENAMETOOLONG;
100           return 0;
101         }
102
103       *ctx = (LP_DIR_CTX *)malloc(sizeof(LP_DIR_CTX));
104       if (*ctx == NULL)
105         {
106           errno = ENOMEM;
107           return 0;
108         }
109       memset(*ctx, '\0', sizeof(LP_DIR_CTX));
110
111       strcpy((*ctx)->filespec,directory);
112       strcat((*ctx)->filespec,"*.*;");
113       (*ctx)->filespec_dsc.dsc$w_length = filespeclen;
114       (*ctx)->filespec_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
115       (*ctx)->filespec_dsc.dsc$b_class = DSC$K_CLASS_S;
116       (*ctx)->filespec_dsc.dsc$a_pointer = (*ctx)->filespec;
117       (*ctx)->result_dsc.dsc$w_length = 0;
118       (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
119       (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D;
120       (*ctx)->result_dsc.dsc$a_pointer = 0;
121     }
122
123   (*ctx)->result_dsc.dsc$w_length = 0;
124   (*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
125   (*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D;
126   (*ctx)->result_dsc.dsc$a_pointer = 0;
127
128   status = lib$find_file(&(*ctx)->filespec_dsc, &(*ctx)->result_dsc,
129                          &(*ctx)->VMS_context, 0, 0, 0, &flags);
130
131   if (status == RMS$_NMF)
132     {
133       errno = 0;
134       vaxc$errno = status;
135       return NULL;
136     }
137
138   if(!$VMS_STATUS_SUCCESS(status))
139     {
140       errno = EVMSERR;
141       vaxc$errno = status;
142       return NULL;
143     }
144
145   /* Quick, cheap and dirty way to discard any device and directory,
146      since we only want file names */
147   l = (*ctx)->result_dsc.dsc$w_length;
148   p = (*ctx)->result_dsc.dsc$a_pointer;
149   r = p;
150   for (; *p; p++)
151     {
152       if (*p == '^' && p[1] != '\0') /* Take care of ODS-5 escapes */
153         {
154           p++;
155         }
156       else if (*p == ':' || *p == '>' || *p == ']')
157         {
158           l -= p + 1 - r;
159           r = p + 1;
160         }
161       else if (*p == ';')
162         {
163           l = p - r;
164           break;
165         }
166     }
167
168   strncpy((*ctx)->result, r, l);
169   (*ctx)->result[l] = '\0';
170   str$free1_dx(&(*ctx)->result_dsc);
171
172   return (*ctx)->result;
173 }
174
175 int LP_find_file_end(LP_DIR_CTX **ctx)
176 {
177   if (ctx != NULL && *ctx != NULL)
178     {
179       int status = lib$find_file_end(&(*ctx)->VMS_context);
180
181       free(*ctx);
182
183       if(!$VMS_STATUS_SUCCESS(status))
184         {
185           errno = EVMSERR;
186           vaxc$errno = status;
187           return 0;
188         }
189       return 1;
190     }
191   errno = EINVAL;
192   return 0;
193 }
194