Subversion Repositories tendra.SVN

Rev

Rev 6 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
6 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
6 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
6 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
6 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
6 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
#include "config.h"
62
#if FS_STDARG
63
#include <stdarg.h>
64
#else
65
#include <varargs.h>
66
#endif
67
#include <sys/types.h>
68
#include <errno.h>
69
#include <sys/stat.h>
70
#include "name.h"
71
#include "utility.h"
72
 
73
#ifdef FS_NO_MODE_T
6 7u83 74
typedef unsigned short mode_t;
2 7u83 75
#endif
76
 
77
#ifndef errno
6 7u83 78
extern int errno;
2 7u83 79
#endif
80
 
81
 
82
/*
83
    INPUT BUFFER
84
 
85
    This buffer is used to store strings in various contexts.
86
*/
87
 
6 7u83 88
char *buffer = null;
2 7u83 89
 
90
 
91
/*
92
    ERROR VARIABLES
93
 
94
    The value exit_status gives the overall status of the program.  It
95
    can be EXIT_SUCCESS or EXIT_FAILURE.  The variable progname gives
96
    the name of the program, which is used in error reports.  filename
97
    and line_no give the current file position.
98
*/
99
 
6 7u83 100
int exit_status = EXIT_SUCCESS;
101
int no_errors = 0;
102
int warnings = 1;
103
char *progname = "tspec";
23 7u83 104
char *progvers = "3.0";
6 7u83 105
time_t progdate = 0;
106
char *filename = null;
107
int line_no = 1;
2 7u83 108
 
109
 
110
/*
111
    PRINT AN ERROR MESSAGE
112
 
113
    This routine prints an error message s (a printf-style string,
114
    which may be followed by any number of arguments) of severity e
115
    (see utility.h).
116
*/
117
 
6 7u83 118
void
119
error(int e, char *s, ...) /* VARARGS */
2 7u83 120
{
6 7u83 121
    va_list args;
122
    char *errtype = null;
123
    boolean show_line = 1;
2 7u83 124
#if FS_STDARG
6 7u83 125
    va_start(args, s);
2 7u83 126
#else
6 7u83 127
    int e;
128
    char *s;
129
    va_start(args);
130
    e = va_arg(args, int);
131
    s = va_arg(args, char *);
2 7u83 132
#endif
6 7u83 133
    switch (e) {
134
	case ERR_FATAL: {
135
	    exit_status = EXIT_FAILURE;
136
	    errtype = "Fatal";
137
	    no_errors++;
138
	    break;
2 7u83 139
	}
6 7u83 140
	case ERR_INTERNAL: {
141
	    exit_status = EXIT_FAILURE;
142
	    errtype = "Internal";
143
	    no_errors++;
144
	    break;
2 7u83 145
	}
6 7u83 146
	case ERR_SERIOUS: {
147
	    exit_status = EXIT_FAILURE;
148
	    errtype = "Error";
149
	    no_errors++;
150
	    break;
2 7u83 151
	}
6 7u83 152
	case ERR_WARNING: {
153
	    if (!warnings) {
154
		va_end(args);
155
		return;
2 7u83 156
	    }
6 7u83 157
	    errtype = "Warning";
158
	    break;
2 7u83 159
	}
6 7u83 160
	case ERR_INFO: {
161
	    errtype = "Info";
162
	    show_line = 0;
163
	    break;
2 7u83 164
	}
165
    }
6 7u83 166
    if (progname)IGNORE fprintf(stderr, "%s: ", progname);
167
    if (errtype)IGNORE fprintf(stderr, "%s: ", errtype);
168
    IGNORE vfprintf(stderr, s, args);
169
    if (filename && show_line) {
170
	IGNORE fprintf(stderr, ", %s, line %d", filename, line_no);
2 7u83 171
    }
6 7u83 172
    IGNORE fprintf(stderr, ".\n");
173
    va_end(args);
174
    if (e == ERR_FATAL)exit(exit_status);
175
    return;
2 7u83 176
}
177
 
178
 
179
/*
180
    ALLOCATE A BLOCK OF MEMORY
181
 
182
    This routine allocates a block of memory of size sz and returns
183
    the result.
184
*/
185
 
6 7u83 186
pointer
187
xalloc(int sz)
2 7u83 188
{
6 7u83 189
    pointer p = (pointer)malloc((size_t)sz);
190
    if (p == null)error(ERR_FATAL, "Memory allocation error");
191
    return(p);
2 7u83 192
}
193
 
194
 
195
/*
196
    REALLOCATE A BLOCK OF MEMORY
197
 
198
    This routine reallocates the block of memory p to have size sz.
199
    xrealloc ( null, sz ) is equivalent to xalloc ( sz ).
200
 
201
*/
202
 
6 7u83 203
pointer
204
xrealloc(pointer p, int sz)
2 7u83 205
{
6 7u83 206
    pointer q;
207
    if (p == null) return(xalloc(sz));
208
    q = (pointer)realloc(p,(size_t)sz);
209
    if (q == null)error(ERR_FATAL, "Memory reallocation error");
210
    return(q);
2 7u83 211
}
212
 
213
 
214
/*
215
    ALLOCATE SPACE FOR A STRING
216
 
217
    This routine allocates space for a string of size n.
218
*/
219
 
6 7u83 220
static char *
221
string_alloc(int n)
2 7u83 222
{
6 7u83 223
    char *r;
224
    if (n >= 1000) {
2 7u83 225
	/* Long strings are allocated space by alloc_nof */
6 7u83 226
	r = alloc_nof(char, n);
2 7u83 227
    } else {
228
	/* Short strings are allocated space from a buffer */
6 7u83 229
	static int no_free = 0;
230
	static char *free_chars = null;
231
	if (n >= no_free) {
232
	    no_free = 1000;
233
	    free_chars = alloc_nof(char, no_free);
2 7u83 234
	}
6 7u83 235
	r = free_chars;
236
	no_free -= n;
237
	free_chars += n;
2 7u83 238
    }
6 7u83 239
    return(r);
2 7u83 240
}
241
 
242
 
243
/*
244
    COPY A STRING
245
 
246
    This routine allocates space for a copy of the string s and copies
247
    the string into this space.  This copy is returned.
248
*/
249
 
6 7u83 250
char *
251
string_copy(char *s)
2 7u83 252
{
6 7u83 253
    int n = (int)strlen(s);
254
    char *r = string_alloc(n + 1);
255
    IGNORE strcpy(r, s);
256
    return(r);
2 7u83 257
}
258
 
259
 
260
/*
261
    CONCATENCATE TWO STRINGS
262
 
263
    This routine allocates space for the concatenation of the strings
264
    s and t.
265
*/
266
 
6 7u83 267
char *
268
string_concat(char *s, char *t)
2 7u83 269
{
6 7u83 270
    int n = (int)strlen(s);
271
    int m = (int)strlen(t);
272
    char *r = string_alloc(n + m + 1);
273
    IGNORE strcpy(r, s);
274
    IGNORE strcpy(r + n, t);
275
    return(r);
2 7u83 276
}
277
 
278
 
279
/*
280
    CONSTRUCT A STRING
281
 
282
    This routine takes a printf string and a list of arguments, and
283
    does a sprintf into a permanent area of memory.
284
*/
285
 
6 7u83 286
char *
287
string_printf(char *s, ...) /* VARARGS */
2 7u83 288
{
6 7u83 289
    va_list args;
2 7u83 290
#if FS_STDARG
6 7u83 291
    va_start(args, s);
2 7u83 292
#else
6 7u83 293
    char *s;
294
    va_start(args);
295
    s = va_arg(args, char *);
2 7u83 296
#endif
6 7u83 297
    IGNORE vsprintf(buffer, s, args);
298
    va_end(args);
299
    return(string_copy(buffer));
2 7u83 300
}
301
 
302
 
303
/*
304
    MODE OF DIRECTORIES CREATED
305
 
306
    The mode of any created directories is determined.  On a truly POSIX
307
    compliant machine, the first branch is taken.
308
*/
309
 
6 7u83 310
#if defined(S_IRWXU) && defined(S_IRWXG) && defined(S_IRWXO)
311
#define  DIRMODE	(S_IRWXU | S_IRWXG | S_IRWXO)
2 7u83 312
#else
6 7u83 313
#if defined(S_IREAD) && defined(S_IWRITE) && defined(S_IEXEC)
314
#define  DIRMODE	(S_IREAD | S_IWRITE | S_IEXEC)
2 7u83 315
#else
316
#define  DIRMODE	0777
317
#endif
318
#endif
319
 
320
 
321
/*
322
    CREATE A DIRECTORY TO PUT A FILE IN
323
 
324
    This routine recursively creates a directory to contain a file
325
    named nm.
326
*/
327
 
6 7u83 328
void
329
create_dir(char *nm)
2 7u83 330
{
6 7u83 331
    struct stat st;
332
    char *dir = dirname(nm);
333
    if (dir == null) return;
334
    if (stat(dir, &st) == 0) return;
2 7u83 335
#ifdef ENOENT
6 7u83 336
    if (errno != ENOENT) {
337
	error(ERR_SERIOUS, "Illegal directory, %s", dir);
338
	return;
2 7u83 339
    }
340
#endif
6 7u83 341
    create_dir(dir);
342
    if (verbose) IGNORE printf("Creating directory, %s ...\n", dir);
343
    if (mkdir(dir,(mode_t)DIRMODE)) {
344
	error(ERR_SERIOUS, "Can't create directory, %s", dir);
345
	return;
2 7u83 346
    }
6 7u83 347
    return;
2 7u83 348
}
349
 
350
 
351
/*
352
    CHECK A FILENAME
353
 
354
    This routine checks the file name nm for excessively long components,
355
    which may cause problems on some machines.
356
*/
357
 
6 7u83 358
void
359
check_name(char *nm)
2 7u83 360
{
6 7u83 361
    char *p;
362
    int i = 0, n = 0;
363
    for (p = nm; *p; p++) {
364
	if (*p == '/') {
365
	    if (i > n)n = i;
366
	    i = 0;
2 7u83 367
	} else {
6 7u83 368
	    i++;
2 7u83 369
	}
370
    }
6 7u83 371
    if (i > n)n = i;
372
    if (n > 14) {
373
	char *err = "The filename %s contains a component of length %d";
374
	error(ERR_WARNING, err, nm, n);
2 7u83 375
    }
6 7u83 376
    return;
2 7u83 377
}
378
 
379
 
380
/*
381
    FIND THE DATE STAMP ON A FILE
382
 
383
    This routine finds the modification time of the file nm.  Zero is
384
    returned for inaccessible files.
385
*/
386
 
6 7u83 387
time_t
388
date_stamp(char *nm)
2 7u83 389
{
6 7u83 390
    struct stat st;
391
    if (nm && stat(nm, &st) == 0) return(st.st_mtime);
392
    return((time_t)0);
2 7u83 393
}