aboutsummaryrefslogtreecommitdiff
path: root/unix/boot/mkpkg/sflist.c
blob: e487df771bfd560d3ebf85a80dd61da40241f5c0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
 */

#include <stdio.h>
#include <ctype.h>
#include <string.h>

#define	import_spp
#define	import_error
#include <iraf.h>

#include "mkpkg.h"
#include "extern.h"
#include "../bootProto.h"


/*
 * SFLIST.C -- Special file list package.  The special file list is a list of
 * library module list source files which need special processing on a given
 * host system.  Examples of such files are files which have been optimized in
 * a machine dependent way, e.g., in assembler or C, or files which must be
 * compiled in a nonstandard way due to host compiler bugs.  The special file
 * list makes this special processing possible without having to modify the
 * mkpkg files in the portable system in a host dependent way, concentrating
 * all knowledge of those parts of the system which have been tailored for the
 * local host into a single, easily modifiable table file stored in HLIB.
 *
 * External functions:
 *
 *	      sf_scanlist (cx)			# parse $special file list
 *  sflist = sf_dirsearch (dirname)		# lookup directory in sflist
 *    sfp = sf_filesearch (sflist, filename)	# lookup file in dir file list
 *	         sf_prune (cp)			# free space in string buffer
 *
 * where
 *
 *	struct	context	*cx;
 *	struct	sfile	*sflist, *sfp;
 *	char		*filename, *dirname;
 *
 * The special file list is organized by source directory to speed searches
 * (most directories will not contain any files needing special processing,
 * eliminating the need to lookup the files in module lists in that directory)
 * and to reduce storage requirements for the list.  The special file database
 * thus consists of a list of directories containing special files, and for
 * each directory, a pointer to a linked list of special file entries, one
 * for each special file in the directory.  Since the organization by directory
 * tends to produce a database consisting of very short file lists, we use a
 * linked list rather than a hash table for the file lists.
 *
 * For each special file we record the standard file name, the pathname of
 * the special file to be used, and a command to be pushed back into the MKPKG
 * command input stream to generate the object file for the module.
 * The special file name may be the same as the standard file name, e.g, if
 * the standard file only needs to be compiled in a nonstandard way.  If the
 * mkobj string is null the special file name will simply be returned in the
 * module list, and compiled with XC using the default compile flags.
 */

static	int	sf_ndirs = 0;			/* no. of directories	*/
static	int	sf_nfiles = 0;			/* no. of special files	*/
static	char	*sf_dirs[MAX_SFDIRS];		/* source directories	*/
static	struct	sfile *sf_flist[MAX_SFDIRS];	/* directory file lists */
static	struct	sfile sf_files[MAX_SFFILES];	/* special file list	*/
static	char	nullstr[] = "";


/* SF_SCANLIST -- Called when the $special macro preprocessor directive is
 * encountered to parse a special file list, entering each file listed into
 * the special file list database.  The syntax of a $special special file
 * list directive is as follows:
 *
 *	$special dirname:
 *		stname1	sfname1	mkobj_command1
 *		stname2	sfname2	mkobj_command2
 *				...
 *		stnameN	sfnameN	mkobj_commandN
 *		;
 *
 * where any string value may optionally be quoted, and the mkobj command
 * strings are optional.  The token "&" in <sfname> or <mkobj_command> is
 * replaced by <stname>.
 */
int
sf_scanlist (
  struct context *cx		/* current mkpkg context */
)
{
	register struct	sfile *sfp;
	register char	*ip, *op, *tp;

	char	dirname[SZ_PATHNAME+1];
	char	stname[SZ_PATHNAME+1];
	char	sfname[SZ_PATHNAME+1];
	char	mkobj[SZ_CMD+SZ_PATHNAME+1];
	char	token[SZ_CMD+1];
	struct	sfile *head, *tail;
	int	tok, nfiles, eol=0;
	char	*old_cp;

	old_cp = cp;			/* mark position in sbuf */
	nfiles = 0;

	/* Get the directory name. */
	if (gettok (cx, token, SZ_LINE) != TOK_FNAME) {
	    warns ("missing directory name in special file list", "");
	    goto err;
	} else
	    os_fpathname (token, dirname, SZ_PATHNAME);

	if (debug) {
	    printf ("scan special file list for directory %s\n",
		debug > 1 ? dirname : token);
	    fflush (stdout);
	}

	/* Advance to the start of the module list. */
	while ((tok = gettok (cx, token, SZ_LINE)) != TOK_BEGIN)
	    if (tok == EOF || tok == TOK_END)
		goto err;

	/* Get a pointer to the last element in the special file list for
	 * the named directory.  If this is the first entry for the named
	 * directory, enter the name in the symbol table and set the sflist
	 * pointer to NULL.
	 */
	if ((head = sf_dirsearch (dirname)) == NULL) {
	    sf_dirs[sf_ndirs++] = putstr (dirname);
	    if (sf_ndirs >= MAX_SFDIRS)
		fatals ("too many special file list directories: %s", dirname);
	    tail = NULL;
	} else {
	    for (tail=sfp=head;  sfp;  sfp=sfp->sf_next)
		tail = sfp;
	}

	/* Read successive entries from the special file list for the named
	 * directory, entering each file at the tail of the list.
	 */
	while (!eol && (tok = gettok (cx, token, SZ_LINE)) != TOK_END) {
	    if (tok == EOF || tok == TOK_END)
		break;

	    /* Get standard file name (module name). */
	    if (tok == TOK_NEWLINE)
		continue;			/* blank line */
	    else if (tok != TOK_FNAME)
		goto badline;
	    else
		strcpy (stname, token);

	    /* Get the special file name. */
	    if ((tok = gettok (cx, sfname, SZ_PATHNAME)) == TOK_END)
		eol++;
	    if (tok != TOK_FNAME)
		goto badline;

	    /* Get the mkobj command string, if any. */
	    if ((tok = gettok (cx, token, SZ_LINE)) == TOK_NEWLINE) {
		mkobj[0] = EOS;
	    } else if (tok == TOK_END) {
		mkobj[0] = EOS;
		eol++;
	    } else if (tok != TOK_FNAME) {
		goto badline;
	    } else {
		/* Extract the command string, expanding any "&" filename
		 * references therein.
		 */
		for (ip=token, op=mkobj;  (*op = *ip++);  op++)
		    if (*op == '&') {
			for (tp=stname;  (*op = *tp++);  op++)
			    ;
			--op;
		    }
	    }

	    if (debug)
		printf ("file %s -> %s, mkobj = `%s'\n",
		    stname, (sfname[0] == '&') ? stname : sfname, mkobj);

	    /* Add the file to the tail of the file list. */
	    nfiles++;
	    sfp = &sf_files[sf_nfiles++];
	    if (sf_nfiles >= MAX_SFFILES)
		fatals ("too many special files: %s", stname);
	    
	    sfp->sf_stname = putstr (stname);
	    sfp->sf_sfname = (sfname[0]=='&') ? sfp->sf_stname : putstr(sfname);
	    sfp->sf_mkobj  = mkobj[0] ? putstr(mkobj) : nullstr;
	    sfp->sf_next   = NULL;

	    if (tail) {
		tail->sf_next = sfp;
		tail = sfp;
	    } else
		sf_flist[sf_ndirs-1] = head = tail = sfp;

	    continue;
badline:
	    /* Print message and discard rest of line, but do not quit. */
	    warns ("bad token `%s' in special file list", token);
	    while (!eol && (tok = gettok (cx, token, SZ_LINE)) != TOK_NEWLINE)
		if (tok == TOK_END)
		    break;
		else if (tok == EOF)
		    goto err;
	}

	if (debug) {
	    printf ("%d special files added; total ndirs=%d, nfiles=%d\n",
		nfiles, sf_ndirs, sf_nfiles);
	    fflush (stdout);
	}

	if (nfiles == 0) {
	    warns ("empty special file list for %s", dirname);
	    sf_prune (cp = old_cp);
	    return (ERR);
	} else
	    return (OK);

err:
	/* Discard rest of directive. */
	while (!eol && (tok = gettok (cx, token, SZ_LINE)) != TOK_END)
	    if (tok == EOF || tok == TOK_END)
		break;

	/* Return memory and sfile database space. */
	sf_prune ((cp = old_cp));

	return (ERR);
}


/* SF_DIRSEARCH -- Search the special file database for the named directory,
 * returning a pointer to the special file list for that directory if the
 * directory is found, else NULL.  Note that directory names are stored as
 * host system pathnames (so that any equivalent form of reference may be used
 * in the mkpkg files), and we assume that we are called with the directory
 * pathname already resolved.
 */
struct sfile *
sf_dirsearch (
  char	*dirname		/* host pathname of directory */
)
{
	register int	i;

	if (debug) {
	    printf ("search sflist for directory %s\n", dirname);
	    fflush (stdout);
	}

	for (i=0;  i < sf_ndirs;  i++)
	    if (h_direq (sf_dirs[i], dirname))
		return (sf_flist[i]);

	return (NULL);
}


/* SF_FILESEARCH -- Search the special file list for a directory for the named
 * file.  File names are stored in the list by the name given in the library
 * module list in the mkpkg file.  If the named file is found a pointer to the
 * special file descriptor for that file is returned, otherwise NULL is
 * returned.  Note that "file*" is a prefix match, whereas "file" requires an
 * exact match.
 */
struct sfile *
sf_filesearch (
  struct sfile *sflist,		/* special file list	*/
  char	*stname 		/* standard file name	*/
)
{
	register struct sfile *sfp;
	register char	*p1, *p2;

	for (sfp=sflist;  sfp;  sfp=sfp->sf_next) {
	    for (p1=sfp->sf_stname, p2=stname;  *p1 && *p1 == *p2;  p1++, p2++)
		;
	    if ((*p1 == EOS && *p2 == EOS) || *p1 == '*')
		return (sfp);
	}
	
	return (NULL);
}


/* SF_PRUNE -- Prune the special file database back to the given point in the
 * string buffer.
 */
void
sf_prune (
  register char	*cp		/* lop off everything here and above */
)
{
	register struct sfile *sfp, *sf_top;
	register int	i;

	/* Prune the directory list. */
	for (i=0;  i < sf_ndirs;  i++)
	    if (sf_dirs[i] >= cp || sf_flist[i]->sf_stname >= cp) {
		sf_ndirs = i;
		break;
	    }

	/* Prune the global file list. */
	for (i=0;  i < sf_nfiles;  i++)
	    if (sf_files[i].sf_stname >= cp) {
		sf_nfiles = i;
		break;
	    }

	/* Prune the individual directory file lists. */
	for (i=0, sf_top = &sf_files[sf_nfiles];  i < sf_nfiles;  i++) {
	    sfp = &sf_files[i];
	    if (sfp->sf_next >= sf_top)
		sfp->sf_next = NULL;
	}
}