This is misc.c in view mode; [Download] [Up]
/*
* Copyright (C) 1985-1992 New York University
*
* This file is part of the Ada/Ed-C system. See the Ada/Ed README file for
* warranty (none) and distribution info and also the GNU General Public
* License for more details.
*/
/* misc.c - miscellaneous programs */
#ifdef PALLOC
#define calloc pcalloc
#define free pfree
#define cfree pcfree
#define malloc pmalloc
#define realloc prealloc
#endif
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "time.h"
#include "ifile.h"
#include "miscprots.h"
#ifndef LIBDIR
#define LIBDIR "/usr/local/lib"
#endif
#ifdef vms
#include <file.h>
#include descrip
#endif
#ifdef ADALIB
#ifdef vms
/*
#include "adalib.h"
*/
#endif
#define EXIT_INTERNAL_ERROR
#endif
#ifdef BINDER
#ifdef vms
/*
#include "adabind.h"
*/
#endif
#define EXIT_INTERNAL_ERROR
extern int adacomp_option;
#endif
#ifdef INT
#ifdef vms
/*
#include "adaexec.h"
*/
#endif
#define EXIT_INTERNAL_ERROR
#endif
#ifndef EXPORT
#undef EXIT_INTERNAL_ERROR
#endif
#ifdef BSD
#include <sys/file.h>
#endif
#ifdef vms
char *DIRECTORY_START = "[."; /* used as the beginning of a VMS dir spec. */
#endif
char *LIBRARY_PREFIX= "";
/* PREDEFNAME gives directory path to predef files.
* libset() is used to toggle between libraries (the users and predef).
* tname = libset(lname) sets library prefix for ifopen, etc. to lname
* and returns prior setting in tname.
*/
static void openerr(char *filename, char *mode);
static void fhlist(IFILE *, char *);
#ifdef DEBUG
#define IOT
int malloctrace = 0;
void trace_malloc() /*;trace_malloc*/
{
malloctrace = 1;
}
#endif
static int ifiles = 0;
#ifdef SMALLOC
unsigned int smalloc_free = 0;
char *smalloc_ptr;
#define SMALLOC_BLOCK 2000
char **smalloc_table = (char **)0;
unsigned smalloc_blocks = 0;
#endif
char *smalloc(unsigned n) /*;smalloc*/
{
/* variant of malloc for use for blocks that will never be freed,
* primarily blocks used for small strings. This permits allocation
* in larger blocks avoiding the malloc overhead required for each block.
*/
#ifndef SMALLOC
return emalloct(n, "smalloc");
#else
char *p;
if (n & 1) n+= 1;
#ifdef ALIGN4
if (n & 2) n+= 2;
#endif
if (n > SMALLOC_BLOCK) { /* large block allocated separately */
#ifdef DEBUG
printf("smalloc: warning block %u exceeds %d SMALLOC_BLOCK\n",
n, SMALLOC_BLOCK);
#endif
p = emalloct(n, "smalloc");
return p;
}
if (n > smalloc_free) {
smalloc_ptr = emalloct(SMALLOC_BLOCK, "smalloc-block");
smalloc_free = SMALLOC_BLOCK;
smalloc_blocks++;
if (smalloc_blocks == 1) {
smalloc_table = (char **) emalloct(sizeof (char **),
"smalloc-table");
}
else { /* reallocate blocks */
smalloc_table = (char **) erealloct((char *)smalloc_table,
sizeof(char **) * (smalloc_blocks), "smalloc-table-realloc");
}
smalloc_table[smalloc_blocks-1] = smalloc_ptr;
}
p = smalloc_ptr;
smalloc_ptr += n;
smalloc_free -= n;
return p;
#endif
}
#ifdef DEBUG
void smalloc_list()
{
int i;
char **st;
st = smalloc_table;
for (i = 0; i < smalloc_blocks; i++) {
printf("%d %ld %x\n", i, *st, *st);
st++;
}
}
#endif
int is_smalloc_block(char *p) /*;is_smalloc_block*/
{
/* returns TRUE is p points within block allocated by smalloc */
#ifdef SMALLOC
#ifdef IBM_PC
/* for PC need to do 32 bit pointer comparisons */
/*
pragma off(segmented_pointer_operations);
*/
#endif
int i;
char **st;
st = smalloc_table;
if (smalloc_blocks == 0) chaos("is_malloc_block - no blocks");
for (i = 0; i < smalloc_blocks; i++) {
if (*st <= p && p < (*st+(SMALLOC_BLOCK-1)))
return TRUE;
st++;
}
return FALSE;
#ifdef IBM_PC
/*
pragma on(segmented_pointer_operations);
*/
#endif
#else
return FALSE;
#endif
}
void capacity(char *s) /*;capacity*/
{
/* called when compiler capacity limit exceeded.
* EXIT_INTERNAL_ERROR is defined when the module is run by itself
* (not spawned from adacomp) and DEBUG is not defined.
*/
#ifdef EXIT_INTERNAL_ERROR
#ifdef vms
LIB$STOP(MSG_CAPACITY);
#else
fprintf(stderr, "capacity limit exceeded: %s\n", s);
exitp(RC_INTERNAL_ERROR);
#endif
#else
#ifdef DEBUG
printf("capacity limit exceeded: %s\nexecution abandoned \n", s);
#endif
fprintf(stderr, "capacity limit exceeded: %s\n", s);
exitp(RC_INTERNAL_ERROR);
#endif
}
#ifdef CHAOS
void chaos(char *s) /*;chaos*/
{
/* called when internal logic error detected and it is not meaningful
* to continue execution. This is never defined for the export version.
*/
fprintf(stderr, "chaos: %s\nexecution abandoned \n", s);
printf("chaos: %s\nexecution abandoned \n", s);
exitp(RC_INTERNAL_ERROR);
}
#else
void exit_internal_error() /*;exit_internal_error*/
{
/* called when internal logic error detected and it is not meaningful
* to continue execution. This procedure is called by the export version.
* EXIT_INTERNAL_ERROR is defined when the module is run by itself
* (not spawned from adacomp) and EXPORT is defined.
* Now that adabind is a separate module which can be called by itself
* or spawned from adacomp, we must test the run time flag adacomp_option
* to determine which case it is.
*/
#ifdef EXIT_INTERNAL_ERROR
#ifdef vms
LIB$STOP(MSG_CHAOS);
#else
#ifdef BINDER
if (adacomp_option)
#endif
fprintf(stderr, "Adaed internal error - Please report.\n");
exit(RC_INTERNAL_ERROR);
#endif
#else
exit(RC_INTERNAL_ERROR);
#endif
}
#endif
void exitp(int n) /*;exitp*/
{
/* synonym for exit() used so can trap exit() calls with debugger */
exit(n);
}
char *ecalloc(unsigned nelem, unsigned nsize) /*;ecalloc */
{
/* calloc with error check if no more */
char *p;
if (nelem > 20000) chaos("ecalloc: ridiculous argument");
p = calloc (nelem, nsize);
if (p == (char *) 0)
capacity("out of memory \n");
return p;
}
char *emalloc(unsigned n) /*;emalloc */
{ /* avoid BUGS - use calloc which presets result to zero ds 3 dec 84*/
/* malloc with error check if no more */
char *p;
if (n > 50000) chaos("emalloc: ridiculous argument");
p = calloc (1, n);
if (p == (char *) 0)
capacity("out of memory \n");
return (p);
}
char *erealloc(char *ptr, unsigned size) /*;eralloc */
{
/* realloc with error check if no more */
char *p;
p = realloc (ptr, size);
if (p == (char *) 0)
capacity("erealloc: out of memory \n");
return (p);
}
char *strjoin(char *s1, char *s2) /*;strjoin */
{
/* return string obtained by concatenating argument strings
* watch for either argument being (char *)0 and treat this as null string
*/
char *s;
if (s1 == (char *)0) s1= "";
if (s2 == (char *)0) s2 = "";
s = smalloc((unsigned) strlen(s1) + strlen(s2) + 1);
strcpy(s, s1);
strcat(s, s2);
return s;
}
int streq(char *a, char *b) /*;streq*/
{
/* test two strings for equality, allowing for null pointers */
if (a == (char *)0 && b == (char *)0)
return TRUE;
else if (a == (char *)0 || b == (char *)0)
return FALSE;
else return (strcmp(a, b) == 0);
}
char *substr(char *s, int i, int j) /*;substr */
{
/* return substring s(i..j) if defined, else return null ptr*/
int n;
char *ts, *t;
if (s == (char *)0) return (char *) 0;
n = strlen(s);
if (!(i > 0 && j <= n && i <= j)) return (char *)0;
/* allocate result, including null byte at end */
ts = smalloc((unsigned) j - i + 2);
t = ts;
s = s + (i - 1); /* point to start of source*/
for (; i <= j; i++) *t++ = *s++; /* copy characters */
*t = '\0'; /* terminate result */
return ts;
}
/* getopt(3) procedure obtained from usenet */
/*
* getopt - get option letter from argv
*/
#ifdef IBM_PC
#define nogetopt
#endif
#ifdef nogetopt
char *optarg; /* Global argument pointer. */
int optind = 0; /* Global argv index. */
static char *scan = NULL; /* Private scan pointer. */
int getopt(int argc, char **argv, char *optstring) /*;getopt */
{
register char c;
register char *place;
optarg = NULL;
if (scan == NULL || *scan == '\0') {
if (optind == 0)
optind++;
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
return (EOF);
if (strcmp (argv[optind], "--") == 0) {
optind++;
return (EOF);
}
scan = argv[optind] + 1;
optind++;
}
c = *scan++;
place = strchr (optstring, c);
if (place == NULL || c == ':') {
fprintf (stderr, "%s: unknown option -%c\n", argv[0], c);
return ('?');
}
place++;
if (*place == ':') {
if (*scan != '\0') {
optarg = scan;
scan = NULL;
}
else {
optarg = argv[optind];
optind++;
}
}
return (c);
}
#endif
char *greentime(int un) /*;greentime*/
{
/* get greenwich time in string of 23 characters.
* format of result is as follows
* 1984 10 02 16 30 36 nnn
* 123456789a123456789b123
* year mo da hr mi se uni
*
* greenwich time is used to avoid problems with daylight savings time.
* The last three characters are the compilation unit number
* (left filled with zeros if necessary).
* NOTE: changed to use local time to give approx. same time as
* SETL version ds 20 nov 84
*/
char *s;
#ifndef IBM_PC
long clock;
#else
/* IBM_PC (Metaware) */
time_t clock;
#endif
/*struct tm *gmtime();*/
struct tm *t;
#ifndef IBM_PC
clock = time(0);
#else
time(&clock);
#endif
s = smalloc(24);
/*t = gmtime(&clock);*/
t = localtime(&clock);
sprintf(s,"%04d %02d %02d %02d %02d %02d %03d",
#ifdef IBM_PC
/* needed until Metaware fixes bug in tm_year field (ds 6-19-86) */
t->tm_year , t->tm_mon + 1, t->tm_mday,
#else
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
#endif
t->tm_hour, t->tm_min, t->tm_sec, un);
return s;
}
FILE *efopenl(char *filename, char *suffix, char *type, char *mode) /*;efopenl*/
{
char *fname;
FILE *f;
fname = ifname(filename, suffix);
f = efopen(fname, type, mode);
efree(fname);
return f;
}
FILE *efopen(char *filename, char *type, char *mode) /*;efopen*/
{
FILE *f;
#ifdef IBM_PC
char *p;
/* mode only meaningful for IBM PC for now */
p = emalloc((unsigned) (strlen(type) + strlen(mode) + 1));
strcpy(p, type);
strcat(p, mode);
f = fopen(filename, p);
efree(p);
#else
f = fopen(filename, type);
#endif
if (f == (FILE *)0)
openerr(filename, type);
return f;
}
void efree(char *p) /*;efree*/
{
/* free with check that not tryig to free null pointer*/
if (p == (char *)0)
chaos("efree: trying to free null pointer");
free(p);
}
int strhash(char *s) /*;strhash*/
{
/* Hashing function from strings to numbers */
register int hash = 0;
/* add character values together, adding in the cumulative hash code
* at each step so that 'ABC' and 'BCA' have different hash codes.
*/
while (*s)
hash += hash + *s++;
if (hash < 0) hash = - hash; /* to avoid negative hash code */
return hash;
}
char *unit_name_type(char *u) /*;unit_name_type*/
{
int n;
char *s;
n = strlen(u);
if (n < 2) {
s = smalloc(1);
*s = '\0';
return s;
}
/* otherwise, return first two characters */
s = smalloc(3);
s[0] = u[0];
s[1] = u[1];
s[2] = '\0';
return s;
}
#ifdef BSD
/* BSD doesn't support strchr() and strrchr(), but they are just
* named index() and rindex(), respectively, so here is code for BSD
*/
char *strchr(char *s, int c)
{
return index(s, (char) c);
}
char *strrchr(char *s, int c)
{
return rindex(s, (char) c);
}
#endif
char *libset(char *lname) /*;libset*/
{
char *old_name;
old_name = LIBRARY_PREFIX;
LIBRARY_PREFIX = lname;
return old_name;
}
char *ifname(char *filename, char *suffix) /*;ifname*/
{
char *fname;
/* allow room for library prefix, file name and suffix */
#ifdef vms
if (strchr(LIBRARY_PREFIX, '[')) {
fname = emalloc((unsigned) (strlen(LIBRARY_PREFIX) +
strlen(filename) + strlen(suffix) + 2));
}
else {
fname = emalloc((unsigned) (strlen(LIBRARY_PREFIX) +
strlen(filename) + strlen(suffix) + 3 + 2));
}
#else
fname = emalloc((unsigned) (strlen(LIBRARY_PREFIX) + strlen(filename) +
strlen(suffix) + 3));
#endif
if (strlen(LIBRARY_PREFIX)) { /* prepend library prefix if present */
#ifdef vms
if (strchr(LIBRARY_PREFIX, '[')) {
strcpy(fname, LIBRARY_PREFIX);
}
else {
strcpy(fname, DIRECTORY_START);
strcat(fname, LIBRARY_PREFIX);
}
#else
strcpy(fname, LIBRARY_PREFIX);
#endif
#ifdef IBM_PC
strcat(fname, "\\");
#endif
#ifdef BSD
strcat(fname, "/");
#endif
#ifdef SYSTEM_V
strcat(fname, "/");
#endif
#ifdef vms
if (!strchr(LIBRARY_PREFIX, '['))
strcat(fname, "]");
#endif
strcat(fname, filename);
}
else {
strcpy(fname, filename); /* copy name if no prefix */
}
if (strlen(suffix)) {
strcat(fname, ".");
strcat(fname, suffix);
}
return fname;
}
IFILE *ifopen(char *filename, char *suffix, char *mode, char *typea,
int trace, int pass) /*;ifopen*/
{
#ifdef HI_LEVEL_IO
FILE *file;
#else
int file;
int flag;
#endif
char ftype, fversion, version;
char type, modec;
char *fname;
long s = 0L;
int nr, opened = FALSE, error = FALSE;
IFILE *ifile;
#ifdef IBM_PC
char *t_name;
#endif
type = typea[0];
modec= mode[0];
#ifdef IOT
if (trace) {
printf("%s ", filename);
}
#endif
fname = ifname(filename, suffix); /* expand file name */
#ifdef IBM_PC
/* mode only meaningful for IBM PC for now */
t_name = emalloc((unsigned) (strlen(mode) + 2));
strcpy(t_name, mode);
strcat(t_name, "b");
file = fopen(fname, t_name);
efree(t_name);
#else
#ifdef HI_LEVEL_IO
file = fopen(fname, mode);
#else
#ifdef vms
if (modec == 'w') {
while(~delete(strjoin(fname, ";")));
}
#endif
if (mode[0] == 'w' || mode[1] == '+') {
flag = O_CREAT | O_RDWR;
}
else {
/* ASSUMING only other possibility is "r" !! */
flag = O_RDONLY;
}
file = open(fname, flag, 0700);
#endif
#endif
#ifdef HI_LEVEL_IO
if (file == (FILE *)0) {
#else
if (file == -1) {
#endif
if (pass)
return (IFILE *) 0;
else
openerr(fname, mode);
}
ifile = (IFILE *) emalloc(sizeof(IFILE));
version = (type == 'a') ? AIS_VERSION : (type == 't') ? TRE_VERSION :
(type == 'l') ? LIB_VERSION : (type == 's') ? STUB_VERSION :
(type == 'p') ? AST_VERSION : '?';
ifiles++;
if (modec == 'w') { /* write header */
/* write long at start to later be replaced with slots offset */
ifile->fh_mode = modec;
ifile->fh_type = type;
ifile->fh_version = version;
ifile->fh_slots = 0;
ifile->fh_units_end = 0;
#ifdef HI_LEVEL_IO
/* will be upated on close */
fwrite((char *) ifile, sizeof(IFILE), 1, file);
#else
write(file, (char *)ifile, sizeof(IFILE));
#endif
}
else if (modec == 'r') { /* read and check header */
#ifdef HI_LEVEL_IO
nr = fread((char *) ifile, sizeof(IFILE), 1, file);
#else
nr = read(file, (char *) ifile, sizeof(IFILE));
#endif
#ifdef HI_LEVEL_IO
if (nr != 1) {
#else
if (nr != sizeof(IFILE)) {
#endif
#ifdef DEBUG
printf("ifopen - unable to read header\n");
#endif
error = TRUE;
}
ftype = ifile->fh_type;
if (!error && ftype != type) {
#ifdef DEBUG
printf("ifopen read wrong type\n");
#endif
error = TRUE;
}
fversion = ifile->fh_version;
if (!error && fversion != version) {
#ifdef DEBUG
printf("open file read wrong version\n");
#endif
error = TRUE;
}
}
if (error) {
openerr(fname, mode);
}
ifile->fh_number = ifiles;/* set count so can match open and close*/
ifile->fh_trace = trace;
ifile->fh_file = file;
ifile->fh_mode = modec;
#ifdef DEBUG
if (ifile->fh_trace) fhlist(ifile, "open");
#endif
efree(fname);
return ifile;
}
static void openerr(char *filename, char *mode) /*;openerr*/
{
/* EXIT_INTERNAL_ERROR is defined when the module is run by itself
* (not spawned from adacomp) and DEBUG is not defined.
*/
#ifdef EXIT_INTERNAL_ERROR
#ifdef vms
struct dsc$descriptor_s file_name;
file_name.dsc$w_length = strlen(filename);
file_name.dsc$b_dtype = DSC$K_DTYPE_T;
file_name.dsc$b_class = DSC$K_CLASS_S;
file_name.dsc$a_pointer = filename;
LIB$SIGNAL(MSG_NOTOPEN, 1, &file_name);
exit();
#else
fprintf(stderr, "Unable to open file %s for %s \n", filename,
(strcmp(mode, "w") == 0 ? "writing"
: (strcmp(mode, "r") == 0 ? "reading"
: (strcmp(mode, "a") == 0 ? "appending"
: mode))));
exit(RC_ABORT);
#endif
#else
fprintf(stderr, "Unable to open file %s for %s \n", filename,
(strcmp(mode, "w") == 0 ? "writing"
: (strcmp(mode, "r") == 0 ? "reading"
: (strcmp(mode, "a") == 0 ? "appending"
: mode))));
exit(RC_ABORT);
#endif
}
void ifclose(IFILE *ifile) /*;ifclose*/
{
#ifdef HI_LEVEL_IO
FILE *file;
#else
int file;
#endif
#ifdef DEBUG
if (ifile->fh_trace) fhlist(ifile, "close");
#endif
file = ifile->fh_file;
/* write out file header if write mode */
if (ifile->fh_mode == 'w') {
ifile->fh_trace = 0; /* trace and number fields internal use only */
ifile->fh_number = 0;
ifile->fh_mode = '\0';
ifseek(ifile, "update-header", 0L, 0);
#ifdef HI_LEVEL_IO
fwrite((char *)ifile, sizeof(IFILE), 1, file);
#else
write(file, (char *)ifile, sizeof(IFILE));
#endif
}
#ifdef HI_LEVEL_IO
if (file == (FILE *)0)
chaos("ifclose: closing unopened file");
fclose(file);
ifile->fh_file = (FILE *)0;
#else
if (file== -1)
chaos("ifclose: closing unopened file");
close(file);
ifile->fh_file = 0;
#endif
}
void ifoclose(IFILE *ifile) /*;ifoclose*/
{
/* close file if still open */
#ifdef HI_LEVEL_IO
if (ifile != (IFILE *) 0 && ifile->fh_file != (FILE *) 0) {
#else
if (ifile != (IFILE *) 0 && ifile->fh_file != 0) {
#endif
ifclose(ifile);
}
}
#ifdef DEBUG
static void fhlist(IFILE *ifile, char *desc) /*;fhlist*/
{
/* list file header if tracing */
printf("%s %c %d%c version %c trace %d", desc, ifile->fh_mode,
ifile->fh_number, ifile->fh_type, ifile->fh_version, ifile->fh_trace);
printf(" slots %ld units_end %ld\n", ifile->fh_slots, ifile->fh_units_end);
}
#endif
long ifseek(IFILE *ifile, char *desc, long offset, int ptr) /*;ifseek*/
{
long begpos, endpos, seekval;
begpos = iftell(ifile);
#ifdef HI_LEVEL_IO
seekval = fseek(ifile->fh_file, offset, ptr);
#else
seekval = lseek(ifile->fh_file, offset, ptr);
#endif
if (seekval == -1) chaos("ifseek: improper seek");
endpos = iftell(ifile);
#ifdef IOT
if (ifile->fh_trace > 1 )
printf("%s seek %d%c from %ld to %ld\n", desc,
ifile->fh_number, ifile->fh_type, begpos, endpos);
#endif
return endpos;
}
long iftell(IFILE *ifile) /*;iftell*/
{
/* ftell, but arg is IFILE */
#ifdef HI_LEVEL_IO
return ftell(ifile->fh_file);
#else
return lseek(ifile->fh_file, 0, 1);
#endif
}
/* define MEAS_ALLOC to measure alloc performance */
#define MEAS_ALLOC
/* this causes each malloc action to write a line to standard output
* formatted as follows:
* code:one of a, r, f
* a allocate block
* r reallocate block
* f free block
* the block address (integer)
* the block length (or zero if not applicable)
* the remainder of the line describes the action
*/
extern FILE *MALFILE;
#ifndef EXPORT
char *emalloct(unsigned n, char *s) /*;emalloct*/
{
char *p;
p = emalloc(n);
#ifdef DEBUG
if (malloctrace) fprintf(MALFILE, "a %ld %u %s\n", p, n, s);
#endif
return p;
}
#endif
#ifndef EXPORT
char *malloct(unsigned n, char *s) /*;malloct*/
{
/* like emalloct, but ok if not able to allocate block */
char *p;
p = malloc(n);
#ifdef DEBUG
if (p != (char *)0 && malloctrace)
fprintf(MALFILE, "a %ld %u %s\n", p, n, s);
#endif
return p;
}
#endif
#ifndef EXPORT
char *ecalloct(unsigned n, unsigned m, char *msg)
{
char *p;
p = ecalloc(n, m);
#ifdef DEBUG
if (malloctrace) fprintf(MALFILE, "a %ld %u %s\n", p, n*m, msg);
#endif
return p;
}
#endif
#ifndef EXPORT
char *erealloct(char *ptr, unsigned size, char *msg) /*;erealloct*/
{
char *p;
p = erealloc(ptr, size);
#ifdef DEBUG
if (p == ptr) return p;
if (malloctrace) /* trace line includes old address before msg */
fprintf(MALFILE, "r %ld %u %ld %s\n", p, size, ptr, msg);
#endif
return p;
}
#endif
#ifndef EXPORT
void efreet(char *p, char *msg) /*;efreet*/
{
#ifdef DEBUG
if (malloctrace) fprintf(MALFILE, "f %ld 0 %s\n", p, msg);
#endif
efree(p);
}
#endif
char *predef_env() /*;predef_env*/
{
#ifndef IBM_PC
char *s = getenv("ADAEDPREDEF");
if (s == (char *)0) s = get_libdir();
return s;
#else
char *getenv();
return getenv("ADAED");
#endif
}
char *get_libdir()
{
char *s = getenv("ADAED");
if (s == (char *)0)
return LIBDIR;
else
return s;
}
char *parsefile(char *s, int *np, int *nb, int *ns) /*;parsefile*/
{
/* Parse file name s, returning the length of prefix, base part, and
* suffix in np, nb, and nl, respectively. A pointer to the start of
* the base part is returned, or the null pointer if no base part.
* The suffix is assumed to begin with period.
* The prefix ends with the last instance of any of the prefix characters.
*/
#ifdef IBM_PC
char *prefix_chars = ":/\\";
#endif
#ifdef BSD
char *prefix_chars = "/";
#endif
#ifdef SYSTEM_V
char *prefix_chars = "/";
#endif
#ifdef vms
char *prefix_chars = ":[]";
#endif
int n,i;
char *pb;
char *p, *p2;
char *suffix_chars = ".";
int have_prefix = 0;
n = strlen(s);
pb = s; /* assume name starts with base */
*ns = 0;
p = s + n; /* point to last (null) character in s */
/* find length of suffix */
/* but if find a prefix character first, then no suffix possible */
for (i = n - 1; i >= 0; i--) {
p--;
for (p2 = prefix_chars; *p2 !='\0';) {
if (*p == *p2++) {
/* (p-s) gives number of characters before suffix */
have_prefix = 1;
break;
}
}
if (!have_prefix) {
for (p2 = suffix_chars; *p2 !='\0';) {
if (*p == *p2++) {
/* (p-s) gives number of characters before suffix */
*ns = n - (p - s);
break;
}
}
}
}
/* find length of prefix */
*np = 0;
p = s + n;
for (i = n - 1; i >= 0; i--) {
p--;
for (p2 = prefix_chars; *p2 !='\0';) {
if (*p == *p2++) {
p++; /* include last delimiter in prefix */
/* (p-s) now gives prefix length*/
*np = (p - s);
pb = p;
break;
}
}
}
/* base is what remains after removing prefix and suffix*/
*nb = n - (*np + *ns);
if (*nb == 0)
pb = (char *)0; /* if no base */
return pb;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.