982 lines
24 KiB
C
982 lines
24 KiB
C
static char sccsid[] = "@(#)01 1.3 src/bos/usr/ccs/lib/libcurses/tic_parse.c, libcurses, bos411, 9428A410j 2/14/94 10:13:34";
|
||
/*
|
||
* COMPONENT_NAME: LIBCURSES
|
||
*
|
||
* FUNCTIONS: High-level parts of the compiler to drive the scanner, etc.
|
||
*
|
||
* ORIGINS: 4, 27
|
||
*
|
||
* This module contains IBM CONFIDENTIAL code. -- (IBM
|
||
* Confidential Restricted when combined with the aggregated
|
||
* modules for this product)
|
||
* SOURCE MATERIALS
|
||
*
|
||
* (C) COPYRIGHT International Business Machines Corp. 1993
|
||
* All Rights Reserved
|
||
* US Government Users Restricted Rights - Use, duplication or
|
||
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
||
*/
|
||
|
||
/* Copyright (c) 1984 AT&T */
|
||
/* All Rights Reserved */
|
||
|
||
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
||
/* The copyright notice above does not evidence any */
|
||
/* actual or intended publication of such source code. */
|
||
|
||
/* #ident "@(#)curses:screen/tic_parse.c 1.15" */
|
||
/*********************************************************************
|
||
* COPYRIGHT NOTICE *
|
||
**********************************************************************
|
||
* This software is copyright (C) 1982 by Pavel Curtis *
|
||
* *
|
||
* Permission is granted to reproduce and distribute *
|
||
* this file by any means so long as no fee is charged *
|
||
* above a nominal handling fee and so long as this *
|
||
* notice is always included in the copies. *
|
||
* *
|
||
* Other rights are reserved except as explicitly granted *
|
||
* by written permission of the author. *
|
||
* Pavel Curtis *
|
||
* Computer Science Dept. *
|
||
* 405 Upson Hall *
|
||
* Cornell University *
|
||
* Ithaca, NY 14853 *
|
||
* *
|
||
* Ph- (607) 256-4934 *
|
||
* *
|
||
* Pavel.Cornell@Udel-Relay (ARPAnet) *
|
||
* decvax!cornell!pavel (UUCPnet) *
|
||
*********************************************************************/
|
||
|
||
/*
|
||
* comp_parse.c -- The high-level (ha!) parts of the compiler,
|
||
* that is, the routines which drive the scanner,
|
||
* etc.
|
||
*
|
||
* $Log: RCS/comp_parse.v $
|
||
* Revision 2.1 82/10/25 14:45:43 pavel
|
||
* Added Copyright Notice
|
||
*
|
||
* Revision 2.0 82/10/24 15:16:39 pavel
|
||
* Beta-one Test Release
|
||
*
|
||
* Revision 1.3 82/08/23 22:29:39 pavel
|
||
* The REAL Alpha-one Release Version
|
||
*
|
||
* Revision 1.2 82/08/19 19:09:53 pavel
|
||
* Alpha Test Release One
|
||
*
|
||
* Revision 1.1 82/08/12 18:37:12 pavel
|
||
* Initial revision
|
||
*
|
||
*
|
||
*/
|
||
|
||
#include <sys/access.h> /* D119325. For the "acl" functions. */
|
||
#include <sys/tcb.h> /* D119325. For the "tcb" function. */
|
||
#include <sys/param.h> /* D119325. For the posix definitions. */
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <locale.h>
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include "curses_inc.h"
|
||
#include "compiler.h"
|
||
#include "object.h"
|
||
#include "tic_msg.h"
|
||
|
||
#define MSGSTR(num,str) catgets(catd,MS_TIC,num,str)
|
||
extern nl_catd catd;
|
||
|
||
extern char check_only;
|
||
|
||
char *string_table;
|
||
int next_free; /* next free character in string_table */
|
||
unsigned int table_size = 0; /* current string_table size */
|
||
short term_names; /* string table offset - current terminal */
|
||
int part2 = 0; /* set to allow old compiled defns to be used */
|
||
int complete = 0; /* 1 if entry done with no forward uses */
|
||
|
||
char *aclbuf = NULL; /* D119325 To store the return of acl_get() */
|
||
char full_path[MAXPATHLEN]; /* D119325 To store the complete path */
|
||
int tcb_flag = 0; /* D119325 To store the tcb value */
|
||
|
||
extern char * destination; /* D119325 From tic_main.c */
|
||
|
||
extern char *acl_get(); /* D119325 From libs.a */
|
||
extern int acl_put(); /* D119325 From libs.a */
|
||
extern int tcb(); /* D119325 From libs.a */
|
||
|
||
|
||
#define TABLESIZE 1024
|
||
|
||
struct use_item
|
||
{
|
||
long offset;
|
||
struct use_item *fptr, *bptr;
|
||
};
|
||
|
||
struct use_header
|
||
{
|
||
struct use_item *head, *tail;
|
||
};
|
||
|
||
struct use_header use_list = {NULL, NULL};
|
||
int use_count = 0;
|
||
|
||
/*
|
||
* The use_list is a doubly-linked list with NULLs terminating the lists:
|
||
*
|
||
* use_item use_item use_item
|
||
* --------- --------- ---------
|
||
* | | | | | | offset
|
||
* |-------| |-------| |-------|
|
||
* | ----+-->| ----+-->| NULL | fptr
|
||
* |-------| |-------| |-------|
|
||
* | NULL |<--+---- |<--+---- | bptr
|
||
* --------- --------- ---------
|
||
* ^ ^
|
||
* | ------------------ |
|
||
* | | | | |
|
||
* +--+---- | ----+---+
|
||
* | | |
|
||
* ------------------
|
||
* head tail
|
||
* use_list
|
||
*
|
||
*/
|
||
|
||
|
||
/*
|
||
* compile()
|
||
*
|
||
* Main loop of the compiler.
|
||
*
|
||
* get_token()
|
||
* if curr_token != NAMES
|
||
* err_abort()
|
||
* while (not at end of file)
|
||
* do an entry
|
||
*
|
||
*/
|
||
|
||
compile()
|
||
{
|
||
char line[LINE_MAX+1];
|
||
int token_type;
|
||
struct use_item *ptr;
|
||
int old_use_count;
|
||
|
||
token_type = get_token();
|
||
|
||
if (token_type != NAMES)
|
||
err_abort(MSGSTR(FILETERM,
|
||
"File does not start with terminal names in column one\n"));
|
||
|
||
while (token_type != EOF)
|
||
token_type = do_entry((struct use_item *) NULL);
|
||
|
||
DEBUG(2, "Starting handling of forward USE's\n", "");
|
||
|
||
for (part2=0; part2<2; part2++) {
|
||
old_use_count = -1;
|
||
DEBUG(2, "\n\nPART %d\n\n", part2);
|
||
while (use_list.head != NULL && old_use_count != use_count)
|
||
{
|
||
old_use_count = use_count;
|
||
for (ptr = use_list.tail; ptr != NULL; ptr = ptr->bptr)
|
||
{
|
||
fseek(stdin, ptr->offset, 0);
|
||
reset_input();
|
||
if ((token_type = get_token()) != NAMES)
|
||
syserr_abort(MSGSTR(TOKSEEK,
|
||
"Token after a seek not NAMES\n"));
|
||
(void) do_entry(ptr);
|
||
if (complete)
|
||
dequeue(ptr);
|
||
}
|
||
|
||
for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
|
||
{
|
||
fseek(stdin, ptr->offset, 0);
|
||
reset_input();
|
||
if ((token_type = get_token()) != NAMES)
|
||
syserr_abort(MSGSTR(TOKSEEK,
|
||
"Token after a seek not NAMES\n"));
|
||
(void) do_entry(ptr);
|
||
if (complete)
|
||
dequeue(ptr);
|
||
}
|
||
|
||
DEBUG(2, "Finished a pass through enqueued forward USE's\n", "");
|
||
}
|
||
}
|
||
|
||
if (use_list.head != NULL && !check_only)
|
||
{
|
||
fprintf(stderr, "\n");
|
||
fprintf(stderr, MSGSTR(LINKERR1,
|
||
"tic: Error in following up use-links. Either there is a loop\n"));
|
||
fprintf(stderr, MSGSTR(LINKERR2,
|
||
"in the links or they reference non-existant terminals.\n"));
|
||
fprintf(stderr, MSGSTR(LINKERR3,
|
||
"The following is a list of the entries involved:\n\n"));
|
||
|
||
for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
|
||
{
|
||
fseek(stdin, ptr->offset, 0);
|
||
fgets(line, LINE_MAX+1, stdin);
|
||
fprintf(stderr, "%s", line);
|
||
}
|
||
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
/* This is a debugging routine only. */
|
||
|
||
dump_list(str)
|
||
char *str;
|
||
{
|
||
struct use_item *ptr;
|
||
char line[LINE_MAX+1];
|
||
|
||
fprintf(stderr, "dump_list %s\n", str);
|
||
for (ptr = use_list.head; ptr != NULL; ptr = ptr->fptr)
|
||
{
|
||
fseek(stdin, ptr->offset, 0);
|
||
fgets(line, LINE_MAX+1, stdin);
|
||
fprintf(stderr, "ptr %x off %d bptr %x fptr %x str %s",
|
||
ptr, ptr->offset, ptr->bptr, ptr->fptr, line);
|
||
}
|
||
fprintf(stderr, "\n");
|
||
}
|
||
|
||
/*
|
||
* int
|
||
* do_entry(item_ptr)
|
||
*
|
||
* Compile one entry. During the first pass, item_ptr is NULL. In pass
|
||
* two, item_ptr points to the current entry in the use_list.
|
||
*
|
||
* found-forward-use = FALSE
|
||
* re-initialise internal arrays
|
||
* save names in string_table
|
||
* get_token()
|
||
* while (not EOF and not NAMES)
|
||
* if found-forward-use
|
||
* do nothing
|
||
* else if 'use'
|
||
* if handle_use() < 0
|
||
* found-forward-use = TRUE
|
||
* else
|
||
* check for existance and type-correctness
|
||
* enter cap into structure
|
||
* if STRING
|
||
* save string in string_table
|
||
* get_token()
|
||
* if ! found-forward-use
|
||
* dump compiled entry into filesystem
|
||
*
|
||
*/
|
||
|
||
int
|
||
do_entry(item_ptr)
|
||
struct use_item *item_ptr;
|
||
{
|
||
long entry_offset;
|
||
register int token_type;
|
||
register struct name_table_entry *entry_ptr;
|
||
int found_forward_use = FALSE;
|
||
short Booleans[MAXBOOLS],
|
||
Numbers[MAXNUMS],
|
||
Strings[MAXSTRINGS];
|
||
|
||
init_structure(Booleans, Numbers, Strings);
|
||
complete = 0;
|
||
term_names = save_str(curr_token.tk_name);
|
||
DEBUG(2, "Starting '%s'\n", curr_token.tk_name);
|
||
entry_offset = curr_file_pos;
|
||
|
||
for (token_type = get_token();
|
||
token_type != EOF && token_type != NAMES;
|
||
token_type = get_token())
|
||
{
|
||
if (found_forward_use)
|
||
/* do nothing */ ;
|
||
else if (strcmp(curr_token.tk_name, "use") == 0)
|
||
{
|
||
if (handle_use(item_ptr, entry_offset,
|
||
Booleans, Numbers, Strings) < 0)
|
||
found_forward_use = TRUE;
|
||
}
|
||
else
|
||
{
|
||
entry_ptr = find_entry(curr_token.tk_name);
|
||
|
||
if (entry_ptr == NOTFOUND) {
|
||
warning(MSGSTR(UNKCAP, "Unknown Capability - '%s'\n"),
|
||
curr_token.tk_name);
|
||
continue;
|
||
}
|
||
|
||
|
||
if (token_type != CANCEL && entry_ptr->nte_type != token_type)
|
||
warning(MSGSTR(BADTYPE,
|
||
"Wrong type used for capability '%s'\n"),
|
||
curr_token.tk_name);
|
||
switch (token_type)
|
||
{
|
||
case CANCEL:
|
||
switch (entry_ptr->nte_type)
|
||
{
|
||
case BOOLEAN:
|
||
Booleans[entry_ptr->nte_index] = -2;
|
||
break;
|
||
|
||
case NUMBER:
|
||
Numbers[entry_ptr->nte_index] = -2;
|
||
break;
|
||
|
||
case STRING:
|
||
Strings[entry_ptr->nte_index] = -2;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case BOOLEAN:
|
||
if (Booleans[entry_ptr->nte_index] == 0)
|
||
Booleans[entry_ptr->nte_index] = TRUE;
|
||
break;
|
||
|
||
case NUMBER:
|
||
if (Numbers[entry_ptr->nte_index] == -1)
|
||
Numbers[entry_ptr->nte_index] =
|
||
curr_token.tk_valnumber;
|
||
break;
|
||
|
||
case STRING:
|
||
if (Strings[entry_ptr->nte_index] == -1)
|
||
Strings[entry_ptr->nte_index] =
|
||
save_str(curr_token.tk_valstring);
|
||
break;
|
||
|
||
default:
|
||
warning(MSGSTR(UNKTOK, "Unknown token type\n"));
|
||
panic_mode(',');
|
||
continue;
|
||
}
|
||
} /* end else cur_token.name != "use" */
|
||
|
||
} /* endwhile (not EOF and not NAMES) */
|
||
|
||
if (found_forward_use)
|
||
return(token_type);
|
||
|
||
dump_structure(Booleans, Numbers, Strings);
|
||
|
||
complete = 1;
|
||
return(token_type);
|
||
}
|
||
|
||
/*
|
||
Change all cancellations to a non-entry.
|
||
For booleans, @ -> false
|
||
For nums, @ -> -1
|
||
For strings, @ -> -1
|
||
|
||
This only has to be done for entries which
|
||
have to be compatible with the pre-Vr3 format.
|
||
*/
|
||
#ifndef NOCANCELCOMPAT
|
||
elim_cancellations(Booleans, Numbers, Strings)
|
||
short Booleans[];
|
||
short Numbers[];
|
||
short Strings[];
|
||
{
|
||
register int i;
|
||
for (i=0; i < BoolCount; i++)
|
||
{
|
||
if (Booleans[i] == -2)
|
||
Booleans[i] = FALSE;
|
||
}
|
||
|
||
for (i=0; i < NumCount; i++)
|
||
{
|
||
if (Numbers[i] == -2)
|
||
Numbers[i] = -1;
|
||
}
|
||
|
||
for (i=0; i < StrCount; i++)
|
||
{
|
||
if (Strings[i] == -2)
|
||
Strings[i] = -1;
|
||
}
|
||
}
|
||
#endif /* NOCANCELCOMPAT */
|
||
/*
|
||
Change the cancellation signal from the -2 used internally to
|
||
the 2 used within the binary.
|
||
*/
|
||
change_cancellations(Booleans)
|
||
short Booleans[];
|
||
{
|
||
register int i;
|
||
for (i=0; i < BoolCount; i++)
|
||
{
|
||
if (Booleans[i] == -2)
|
||
Booleans[i] = 2;
|
||
}
|
||
|
||
}
|
||
|
||
/*
|
||
* enqueue(offset)
|
||
*
|
||
* Put a record of the given offset onto the use-list.
|
||
*
|
||
*/
|
||
|
||
enqueue(offset)
|
||
long offset;
|
||
{
|
||
struct use_item *item;
|
||
char *malloc();
|
||
|
||
item = (struct use_item *) malloc(sizeof(struct use_item));
|
||
|
||
if (item == NULL)
|
||
syserr_abort(MSGSTR(NOMEM,
|
||
"Not enough memory for use_list element\n"));
|
||
|
||
item->offset = offset;
|
||
|
||
if (use_list.head != NULL)
|
||
{
|
||
item->bptr = use_list.tail;
|
||
use_list.tail->fptr = item;
|
||
item->fptr = NULL;
|
||
use_list.tail = item;
|
||
}
|
||
else
|
||
{
|
||
use_list.tail = use_list.head = item;
|
||
item->fptr = item->bptr = NULL;
|
||
}
|
||
|
||
use_count ++;
|
||
}
|
||
|
||
/*
|
||
* dequeue(ptr)
|
||
*
|
||
* remove the pointed-to item from the use_list
|
||
*
|
||
*/
|
||
|
||
dequeue(ptr)
|
||
struct use_item *ptr;
|
||
{
|
||
if (ptr->fptr == NULL)
|
||
use_list.tail = ptr->bptr;
|
||
else
|
||
(ptr->fptr)->bptr = ptr->bptr;
|
||
|
||
if (ptr->bptr == NULL)
|
||
use_list.head = ptr->fptr;
|
||
else
|
||
(ptr->bptr)->fptr = ptr->fptr;
|
||
|
||
use_count --;
|
||
}
|
||
|
||
/*
|
||
* invalid_term_name(name)
|
||
*
|
||
* Look for invalid characters in a term name. These include
|
||
* space, tab and '/'.
|
||
*
|
||
* Generate an error message if given name does not begin with a
|
||
* digit or letter, then exit.
|
||
*
|
||
* return TRUE if name is invalid.
|
||
*
|
||
*/
|
||
|
||
static int invalid_term_name(name)
|
||
register char *name;
|
||
{
|
||
int error = 0;
|
||
if (! isdigit(*name) && ! islower(*name) && ! isupper(*name))
|
||
error++;
|
||
|
||
for ( ; *name ; name++)
|
||
if (isalnum(*name))
|
||
continue;
|
||
else if (isspace(*name) || (*name == '/'))
|
||
return 1;
|
||
if (error)
|
||
{
|
||
fprintf(stderr, MSGSTR(ILLTERM,
|
||
"tic: Line %d: Illegal terminal name - '%s'\n"), curr_line, name);
|
||
fprintf(stderr, MSGSTR(ILLTERM2,
|
||
"Terminal names must start with a letter or digit\n"));
|
||
exit(1);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* dump_structure()
|
||
*
|
||
* Save the compiled version of a description in the filesystem.
|
||
*
|
||
* make a copy of the name-list
|
||
* break it up into first-name and all-but-last-name
|
||
* if necessary
|
||
* clear CANCELS out of the structure
|
||
* creat(first-name)
|
||
* write object information to first-name
|
||
* close(first-name)
|
||
* for each valid name
|
||
* link to first-name
|
||
*
|
||
*/
|
||
|
||
dump_structure(Booleans, Numbers, Strings)
|
||
short Booleans[];
|
||
short Numbers[];
|
||
short Strings[];
|
||
{
|
||
struct stat statbuf;
|
||
FILE *fp;
|
||
char name_list[PATH_MAX];
|
||
register char *first_name, *other_names, *cur_name;
|
||
char filename[PATH_MAX];
|
||
char linkname[PATH_MAX];
|
||
int len;
|
||
int alphastart = 0;
|
||
extern char *strchr(), *strrchr();
|
||
|
||
strcpy(name_list, term_names + string_table);
|
||
DEBUG(7, "Name list = '%s'\n", name_list);
|
||
|
||
first_name = name_list;
|
||
/* Set othernames to 1 past first '|' in the list. */
|
||
/* Null out that '|' in the process. */
|
||
other_names = strchr(first_name, '|');
|
||
if (other_names)
|
||
*other_names++ = '\0';
|
||
|
||
if (invalid_term_name(first_name))
|
||
warning(MSGSTR(BADFIRST,
|
||
"'%s': bad first term name.\n"), first_name);
|
||
|
||
|
||
DEBUG(7, "First name = '%s'\n", first_name);
|
||
DEBUG(7, "Other names = '%s'\n", other_names ? other_names : "NULL");
|
||
|
||
if ((len = strlen(first_name)) > FILENAME_MAX)
|
||
warning(MSGSTR(TOOLONG,
|
||
"'%s': terminal name too long.\n"), first_name);
|
||
else if (len == 1)
|
||
warning(MSGSTR(TOOSHORT,
|
||
"'%s': terminal name too short.\n"), first_name);
|
||
|
||
check_dir(first_name[0]);
|
||
|
||
strcpy(full_path, destination); /* D119325 */
|
||
strcat(full_path,"/"); /* D119325 */
|
||
|
||
sprintf(filename, "%c/%.*s", first_name[0], PATH_MAX-2, first_name);
|
||
|
||
strcat(full_path,filename); /* D119325 */
|
||
aclbuf = acl_get(full_path); /* D119325 */
|
||
tcb_flag = tcb(full_path, TCB_QUERY); /* D119325 */
|
||
|
||
|
||
if (stat(filename, &statbuf) >= 0 && statbuf.st_mtime >= start_time)
|
||
{
|
||
warning(MSGSTR(MULTDEF,
|
||
"'%s' defined in more than one entry.\n"), first_name);
|
||
fprintf(stderr, MSGSTR(MULTDEF2, "Entry being used is '%s'.\n"),
|
||
(unsigned) term_names + string_table);
|
||
}
|
||
|
||
if (!check_only) {
|
||
unlink(filename);
|
||
fp = fopen(filename, "w");
|
||
if (fp == NULL)
|
||
{
|
||
perror(filename);
|
||
syserr_abort(MSGSTR(CANTOPN2,
|
||
"Can't open %s/%s\n"), destination, filename);
|
||
}
|
||
DEBUG(1, "Created %s\n", filename);
|
||
}
|
||
else DEBUG(1, "Would have created %s\n", filename);
|
||
|
||
#ifndef NOCANCELCOMPAT
|
||
/* if there is no '+' in the name, eliminate */
|
||
/* cancellation markings. */
|
||
if (strchr(first_name, '+') == 0)
|
||
elim_cancellations(Booleans, Numbers, Strings);
|
||
else
|
||
#endif /* NOCANCELCOMPAT */
|
||
change_cancellations(Booleans);
|
||
|
||
if (!check_only) {
|
||
if (write_object(fp, Booleans, Numbers, Strings) < 0)
|
||
{
|
||
syserr_abort(MSGSTR(WRITERR,
|
||
"Error in writing %s/%s\n"), destination, filename);
|
||
}
|
||
fclose(fp);
|
||
|
||
if (aclbuf) /* D119325 */
|
||
acl_put(full_path, aclbuf, 1); /* D119325 */
|
||
if (tcb_flag) /* D119325 */
|
||
tcb(full_path, tcb_flag); /* D119325 */
|
||
|
||
}
|
||
|
||
alphastart = isalpha(first_name[0]);
|
||
|
||
while (other_names)
|
||
{
|
||
cur_name = other_names;
|
||
other_names = strchr(cur_name, '|');
|
||
if (other_names)
|
||
*other_names++ = '\0';
|
||
if (*cur_name == '\0')
|
||
continue;
|
||
|
||
if ((len = strlen(cur_name)) > FILENAME_MAX)
|
||
{
|
||
warning(MSGSTR(TOOLONG,
|
||
"'%s': terminal name too long.\n"), cur_name);
|
||
continue;
|
||
}
|
||
else if (len == 1)
|
||
{
|
||
warning(MSGSTR(TOOSHORT,
|
||
"'%s': terminal name too short.\n"), cur_name);
|
||
continue;
|
||
}
|
||
|
||
if (invalid_term_name(cur_name))
|
||
{
|
||
if (other_names)
|
||
warning(MSGSTR(BADTERM,
|
||
"'%s': bad term name found in list.\n"), cur_name);
|
||
continue;
|
||
}
|
||
|
||
check_dir(cur_name[0]);
|
||
|
||
strcpy(full_path, destination); /* D119325 */
|
||
strcat(full_path,"/"); /* D119325 */
|
||
|
||
|
||
sprintf(linkname, "%c/%.*s", cur_name[0], PATH_MAX-2, cur_name);
|
||
|
||
alphastart |= isalpha(cur_name[0]);
|
||
|
||
if (strcmp(first_name, cur_name) == 0)
|
||
{
|
||
warning(MSGSTR(TERMSYN,
|
||
"Terminal name '%s' synonym for itself\n"), first_name);
|
||
}
|
||
else {
|
||
if (!check_only) {
|
||
|
||
strcat(full_path,linkname); /* D119325 */
|
||
aclbuf = acl_get(full_path); /* D119325 */
|
||
tcb_flag = tcb(full_path, TCB_QUERY); /* D119325 */
|
||
|
||
if (stat(linkname, &statbuf) >= 0 &&
|
||
statbuf.st_mtime >= start_time) {
|
||
warning(MSGSTR(MULTDEF,
|
||
"'%s' defined in more than one entry.\n"),
|
||
cur_name);
|
||
fprintf(stderr, MSGSTR(MULTDEF2,
|
||
"Entry being used is '%s'.\n"),
|
||
(unsigned) term_names + string_table);
|
||
}
|
||
unlink(linkname);
|
||
if (link(filename, linkname) < 0)
|
||
syserr_abort(MSGSTR(CANTLINK,
|
||
"Can't link %s to %s\n"), filename, linkname);
|
||
DEBUG(1, "Linked %s\n", linkname);
|
||
|
||
if (aclbuf) /* D119325 */
|
||
acl_put(full_path, aclbuf, 1); /* D119325 */
|
||
if (tcb_flag) /* D119325 */
|
||
tcb(full_path, tcb_flag); /* D119325 */
|
||
|
||
}
|
||
else DEBUG(1, "Would have linked %s\n", linkname);
|
||
}
|
||
}
|
||
|
||
if (!alphastart)
|
||
{
|
||
warning(MSGSTR(ONESYN,
|
||
"At least one synonym should begin with a letter.\n"));
|
||
}
|
||
}
|
||
|
||
/*
|
||
* int
|
||
* write_object(fp, Booleans, Numbers, Strings)
|
||
*
|
||
* Write out the compiled entry to the given file.
|
||
* Return 0 if OK or -1 if not.
|
||
*
|
||
*/
|
||
|
||
#define swap(x) (((x >> 8) & 0377) + 256 * (x & 0377))
|
||
|
||
#define might_swap(x) (must_swap() ? swap(x) : (x))
|
||
|
||
|
||
int
|
||
write_object(fp, Booleans, Numbers, Strings)
|
||
FILE *fp;
|
||
short Booleans[];
|
||
short Numbers[];
|
||
short Strings[];
|
||
{
|
||
struct header header;
|
||
char *namelist;
|
||
short namelen;
|
||
char zero = '\0';
|
||
register int i;
|
||
char cBooleans[MAXBOOLS];
|
||
register int l_next_free;
|
||
|
||
namelist = term_names + string_table;
|
||
namelen = strlen(namelist) + 1;
|
||
|
||
l_next_free = next_free;
|
||
if (l_next_free % 256 == 255)
|
||
l_next_free++;
|
||
|
||
if (must_swap())
|
||
{
|
||
header.magic = swap(MAGIC);
|
||
header.name_size = swap(namelen);
|
||
header.bool_count = swap(BoolCount);
|
||
header.num_count = swap(NumCount);
|
||
header.str_count = swap(StrCount);
|
||
header.str_size = swap(l_next_free);
|
||
}
|
||
else
|
||
{
|
||
header.magic = MAGIC;
|
||
header.name_size = namelen;
|
||
header.bool_count = BoolCount;
|
||
header.num_count = NumCount;
|
||
header.str_count = StrCount;
|
||
header.str_size = l_next_free;
|
||
}
|
||
|
||
for (i=0; i < BoolCount; i++)
|
||
cBooleans[i] = Booleans[i];
|
||
|
||
if (fwrite(&header, sizeof(header), 1, fp) != 1
|
||
|| fwrite(namelist, sizeof(char), namelen, fp) != namelen
|
||
|| fwrite(cBooleans, sizeof(char), BoolCount, fp) != BoolCount)
|
||
return(-1);
|
||
|
||
if ((namelen+BoolCount) % 2 != 0 && fwrite(&zero, sizeof(char), 1, fp) != 1)
|
||
return(-1);
|
||
|
||
if (must_swap())
|
||
{
|
||
for (i=0; i < NumCount; i++)
|
||
Numbers[i] = swap(Numbers[i]);
|
||
for (i=0; i < StrCount; i++)
|
||
Strings[i] = swap(Strings[i]);
|
||
}
|
||
|
||
if (fwrite((char *)Numbers, sizeof(short), NumCount, fp) != NumCount
|
||
|| fwrite((char *)Strings, sizeof(short), StrCount, fp)
|
||
!= StrCount
|
||
|| fwrite(string_table, sizeof(char), l_next_free, fp)
|
||
!= l_next_free)
|
||
return(-1);
|
||
|
||
return(0);
|
||
}
|
||
|
||
/*
|
||
* int
|
||
* save_str(string)
|
||
*
|
||
* copy string into next free part of string_table, doing a realloc()
|
||
* if necessary. return offset of beginning of string from start of
|
||
* string_table.
|
||
*
|
||
*/
|
||
|
||
int
|
||
save_str(string)
|
||
char *string;
|
||
{
|
||
char *malloc(), *realloc();
|
||
int old_next_free;
|
||
|
||
/* Do not let an offset be 255. It reads as -1 in Vr2 binaries. */
|
||
if (next_free % 256 == 255)
|
||
next_free++;
|
||
|
||
old_next_free = next_free;
|
||
|
||
if (table_size == 0)
|
||
{
|
||
if ((string_table = malloc(TABLESIZE)) == NULL)
|
||
syserr_abort(MSGSTR(OOMEM, "Out of memory\n"));
|
||
table_size = TABLESIZE;
|
||
DEBUG(5, "Made initial string table allocation. Size is %u\n",
|
||
table_size);
|
||
}
|
||
|
||
while (table_size < next_free + strlen(string))
|
||
{
|
||
if ((string_table = realloc(string_table, table_size + TABLESIZE))
|
||
== NULL)
|
||
syserr_abort(MSGSTR(OOMEM, "Out of memory\n"));
|
||
table_size += TABLESIZE;
|
||
DEBUG(5, "Extended string table. Size now %u\n", table_size);
|
||
}
|
||
|
||
strcpy(&string_table[next_free], string);
|
||
DEBUG(7, "Saved string '%s' ", string);
|
||
DEBUG(7, "at location %d\n", next_free);
|
||
next_free += strlen(string) + 1;
|
||
|
||
return(old_next_free);
|
||
}
|
||
|
||
/*
|
||
* init_structure(Booleans, Numbers, Strings)
|
||
*
|
||
* Initialise the given arrays
|
||
* Reset the next_free counter to zero.
|
||
*
|
||
*/
|
||
|
||
init_structure(Booleans, Numbers, Strings)
|
||
short Booleans[];
|
||
short Numbers[], Strings[];
|
||
{
|
||
int i;
|
||
|
||
for (i=0; i < BoolCount; i++)
|
||
Booleans[i] = FALSE;
|
||
|
||
for (i=0; i < NumCount; i++)
|
||
Numbers[i] = -1;
|
||
|
||
for (i=0; i < StrCount; i++)
|
||
Strings[i] = -1;
|
||
|
||
next_free = 0;
|
||
}
|
||
|
||
/*
|
||
** int
|
||
** handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
|
||
**
|
||
** Merge the compiled file whose name is in cur_token.valstring
|
||
** with the current entry.
|
||
**
|
||
** if it's a forward use-link
|
||
** if item_ptr == NULL
|
||
** queue it up for later handling
|
||
** else
|
||
** ignore it (we're already going through the queue)
|
||
** else it's a backward use-link
|
||
** read in the object file for that terminal
|
||
** merge contents with current structure
|
||
**
|
||
** Returned value is 0 if it was a backward link and we
|
||
** successfully read it in, -1 if a forward link.
|
||
*/
|
||
|
||
int
|
||
handle_use(item_ptr, entry_offset, Booleans, Numbers, Strings)
|
||
long entry_offset;
|
||
struct use_item *item_ptr;
|
||
short Booleans[];
|
||
short Numbers[];
|
||
short Strings[];
|
||
{
|
||
struct _bool_struct use_bools;
|
||
struct _num_struct use_nums;
|
||
struct _str_struct use_strs;
|
||
struct stat statbuf;
|
||
char filename[50];
|
||
int i;
|
||
char *UB = &use_bools._auto_left_margin;/* first bool */
|
||
short *UN = &use_nums._columns; /* first num */
|
||
char **US = &use_strs.strs._back_tab; /* first str */
|
||
|
||
if (invalid_term_name(curr_token.tk_valstring))
|
||
warning(MSGSTR(BADTERM2, "%s: bad term name\n"),
|
||
curr_token.tk_valstring);
|
||
|
||
sprintf(filename, "%c/%s", curr_token.tk_valstring[0],
|
||
curr_token.tk_valstring);
|
||
|
||
if (stat(filename, &statbuf) < 0 || part2==0 && statbuf.st_mtime < start_time)
|
||
{
|
||
DEBUG(2, "Forward USE to %s", curr_token.tk_valstring);
|
||
|
||
if (item_ptr == NULL)
|
||
{
|
||
DEBUG(2, " (enqueued)\n", "");
|
||
enqueue(entry_offset);
|
||
}
|
||
else
|
||
DEBUG(2, " (skipped)\n", "");
|
||
|
||
return(-1);
|
||
}
|
||
else
|
||
{
|
||
DEBUG(2, "Backward USE to %s\n", curr_token.tk_valstring);
|
||
if (read_entry(filename, &use_bools, &use_nums, &use_strs) < 0)
|
||
syserr_abort(MSGSTR(REREAD,
|
||
"Error in re-reading compiled file %s\n"), filename);
|
||
|
||
for (i=0; i < BoolCount; i++)
|
||
{
|
||
if (Booleans[i] == FALSE)
|
||
if (UB[i] == TRUE) /* now true */
|
||
Booleans[i] = TRUE;
|
||
else if (UB[i] > TRUE) /* cancelled */
|
||
Booleans[i] = -2;
|
||
}
|
||
|
||
for (i=0; i < NumCount; i++)
|
||
{
|
||
if (Numbers[i] == -1)
|
||
Numbers[i] = UN[i];
|
||
}
|
||
|
||
for (i=0; i < StrCount; i++)
|
||
{
|
||
if (Strings[i] == -1)
|
||
if (US[i] == (char *) -1)
|
||
Strings[i] = -2;
|
||
else if (US[i] != (char *) 0)
|
||
Strings[i] = save_str(US[i]);
|
||
}
|
||
|
||
}
|
||
return(0);
|
||
}
|