Experiment with porting SGML to YAP, and trying to preserve SWI code as much
as possible.
This commit is contained in:
747
packages/sgml/util.c
Normal file
747
packages/sgml/util.c
Normal file
@@ -0,0 +1,747 @@
|
||||
/* $Id$
|
||||
|
||||
Part of SWI-Prolog
|
||||
|
||||
Author: Jan Wielemaker
|
||||
E-mail: jan@swi.psy.uva.nl
|
||||
WWW: http://www.swi-prolog.org
|
||||
Copyright (C): 1985-2002, University of Amsterdam
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _ISOC99_SOURCE 1 /* fwprintf(), etc prototypes */
|
||||
|
||||
#define UTIL_H_IMPLEMENTATION
|
||||
#include "util.h"
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <wctype.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include "utf8.h"
|
||||
|
||||
size_t
|
||||
istrlen(const ichar *s)
|
||||
{ size_t len =0;
|
||||
|
||||
while(*s++)
|
||||
len++;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrdup(const ichar *s)
|
||||
{ if ( s )
|
||||
{ ichar *dup = sgml_malloc((istrlen(s)+1)*sizeof(ichar));
|
||||
ichar *d = dup;
|
||||
|
||||
while(*s)
|
||||
*d++ = *s++;
|
||||
*d = 0;
|
||||
|
||||
return dup;
|
||||
} else
|
||||
{ return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrndup(const ichar *s, int len)
|
||||
{ ichar *dup = sgml_malloc((len+1)*sizeof(ichar));
|
||||
ichar *d = dup;
|
||||
|
||||
while(--len >= 0)
|
||||
*d++ = *s++;
|
||||
*d = 0;
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrcpy(ichar *d, const ichar *s)
|
||||
{ ichar *r = d;
|
||||
|
||||
while(*s)
|
||||
*d++ = *s++;
|
||||
*d = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrcat(ichar *d, const ichar *s)
|
||||
{ ichar *r = d;
|
||||
|
||||
d += istrlen(d);
|
||||
istrcpy(d, s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrncpy(ichar *d, const ichar *s, size_t len)
|
||||
{ ichar *r = d;
|
||||
|
||||
while(*s && len-- > 0)
|
||||
*d++ = *s++;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
istrcaseeq(const ichar *s1, const ichar *s2)
|
||||
{ ichar c;
|
||||
|
||||
while ((c = *s1++) != '\0')
|
||||
{ if (towlower(*s2++) != towlower(c))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return *s2 == '\0';
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
istreq(const ichar *s1, const ichar *s2)
|
||||
{ while(*s1 && *s1 == *s2)
|
||||
s1++, s2++;
|
||||
|
||||
if ( *s1 == 0 && *s2 == 0 )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
istrncaseeq(const ichar *s1, const ichar *s2, int len)
|
||||
{ while(--len >= 0 && towlower(*s1) == towlower(*s2))
|
||||
s1++, s2++;
|
||||
|
||||
if ( len < 0 )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
istrprefix(const ichar *pref, const ichar *s)
|
||||
{ while(*pref && *pref == *s)
|
||||
pref++, s++;
|
||||
|
||||
if ( *pref == 0 )
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrchr(const ichar *s, int c)
|
||||
{ for( ; *s; s++ )
|
||||
{ if ( c == *s )
|
||||
return (ichar *)s;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrupper(ichar *s)
|
||||
{ ichar *r = s;
|
||||
|
||||
for( ; *s; s++)
|
||||
*s = toupper(*s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
istrlower(ichar *s)
|
||||
{ ichar *r = s;
|
||||
|
||||
for( ; *s; s++)
|
||||
*s = towlower(*s);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
istrhash(const ichar *t, int tsize)
|
||||
{ unsigned int value = 0;
|
||||
unsigned int shift = 5;
|
||||
|
||||
while(*t)
|
||||
{ unsigned int c = *t++;
|
||||
|
||||
c -= 'a';
|
||||
value ^= c << (shift & 0xf);
|
||||
shift ^= c;
|
||||
}
|
||||
|
||||
value = value ^ (value >> 16);
|
||||
|
||||
return value % tsize;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
istrcasehash(const ichar *t, int tsize)
|
||||
{ unsigned int value = 0;
|
||||
unsigned int shift = 5;
|
||||
|
||||
while(*t)
|
||||
{ unsigned int c = towlower(*t++); /* case insensitive */
|
||||
|
||||
c -= 'a';
|
||||
value ^= c << (shift & 0xf);
|
||||
shift ^= c;
|
||||
}
|
||||
|
||||
value = value ^ (value >> 16);
|
||||
|
||||
return value % tsize;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
istrtol(const ichar *s, long *val)
|
||||
{ long v;
|
||||
ichar *e;
|
||||
|
||||
if ( *s )
|
||||
{ v = wcstol(s, &e, 10);
|
||||
if ( !e[0] && errno != ERANGE )
|
||||
{ *val = v;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************
|
||||
* INPUT CHARACTER BUFFER *
|
||||
*******************************/
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Input character buffer is used to collect data between SGML markup, such
|
||||
as <...>
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
icharbuf *
|
||||
new_icharbuf()
|
||||
{ icharbuf *buf = sgml_malloc(sizeof(*buf));
|
||||
|
||||
buf->allocated = 0;
|
||||
buf->size = 0;
|
||||
buf->data = NULL;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_icharbuf(icharbuf *buf)
|
||||
{ if ( buf->data )
|
||||
sgml_free(buf->data);
|
||||
|
||||
sgml_free(buf);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__add_icharbuf(icharbuf *buf, int chr)
|
||||
{ if ( buf->size == buf->allocated )
|
||||
{ buf->allocated = (buf->allocated ? buf->allocated*2 : 128);
|
||||
|
||||
if ( buf->data )
|
||||
buf->data = sgml_realloc(buf->data, buf->allocated*sizeof(ichar));
|
||||
else
|
||||
buf->data = sgml_malloc(buf->allocated*sizeof(ichar));
|
||||
}
|
||||
|
||||
buf->data[buf->size++] = chr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
del_icharbuf(icharbuf *buf)
|
||||
{ if ( buf->size > 0 )
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
terminate_icharbuf(icharbuf *buf)
|
||||
{ add_icharbuf(buf, '\0');
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
empty_icharbuf(icharbuf *buf)
|
||||
{ buf->size = 0;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* OUTPUT CHARACTER BUFFER *
|
||||
*******************************/
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Output character buffer deals with two representations: ISO Latin-1 and
|
||||
UCS. It starts life as ISO Latin-1 and is upgraded to UCS as the first
|
||||
character that doesn't fit ISO Latin-1 is added to the buffer.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
ocharbuf *
|
||||
init_ocharbuf(ocharbuf *buf)
|
||||
{ buf->size = 0;
|
||||
buf->allocated = sizeof(buf->localbuf)/sizeof(wchar_t);
|
||||
buf->data.w = buf->localbuf;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
ocharbuf *
|
||||
new_ocharbuf()
|
||||
{ ocharbuf *buf = sgml_malloc(sizeof(*buf));
|
||||
|
||||
return init_ocharbuf(buf);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_ocharbuf(ocharbuf *buf)
|
||||
{ if ( buf->data.w && buf->data.w != buf->localbuf )
|
||||
sgml_free(buf->data.w);
|
||||
|
||||
sgml_free(buf);
|
||||
}
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Make sure the data of the buffer is malloc'ed and nul-terminated.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
ocharbuf *
|
||||
malloc_ocharbuf(ocharbuf *buf)
|
||||
{ if ( buf->data.w == buf->localbuf )
|
||||
{ int bytes = (buf->size+1) * sizeof(wchar_t);
|
||||
|
||||
buf->data.w = sgml_malloc(bytes);
|
||||
memcpy(buf->data.w, buf->localbuf, bytes);
|
||||
buf->data.w[buf->size] = 0;
|
||||
} else
|
||||
terminate_ocharbuf(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
add_ocharbuf(ocharbuf *buf, int chr)
|
||||
{ if ( buf->size == buf->allocated )
|
||||
{ buf->allocated *= 2;
|
||||
|
||||
if ( buf->data.w != (wchar_t*)buf->localbuf )
|
||||
{ buf->data.w = sgml_realloc(buf->data.w, buf->allocated*sizeof(wchar_t));
|
||||
} else
|
||||
{ buf->data.w = sgml_malloc(buf->allocated*sizeof(wchar_t));
|
||||
memcpy(buf->data.w, buf->localbuf, sizeof(buf->localbuf));
|
||||
}
|
||||
}
|
||||
buf->data.w[buf->size++] = chr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
del_ocharbuf(ocharbuf *buf)
|
||||
{ if ( buf->size > 0 )
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
terminate_ocharbuf(ocharbuf *buf)
|
||||
{ add_ocharbuf(buf, '\0');
|
||||
buf->size--;
|
||||
}
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
empty_ocharbuf() frees the associated buffer after a big lump has been
|
||||
in it. Otherwise it simply sets the size to 0.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
void
|
||||
empty_ocharbuf(ocharbuf *buf)
|
||||
{ buf->size = 0;
|
||||
|
||||
if ( buf->allocated > 8192 )
|
||||
{ assert(buf->data.w != buf->localbuf);
|
||||
sgml_free(buf->data.w);
|
||||
|
||||
buf->allocated = sizeof(buf->localbuf)/sizeof(wchar_t);
|
||||
buf->data.w = buf->localbuf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* BUFFER RING *
|
||||
*******************************/
|
||||
|
||||
#define RINGSIZE 16
|
||||
static void *ring[RINGSIZE];
|
||||
static int ringp;
|
||||
|
||||
wchar_t *
|
||||
str2ring(const wchar_t *in)
|
||||
{ wchar_t *copy = sgml_malloc((wcslen(in)+1)*sizeof(wchar_t));
|
||||
|
||||
if ( !copy )
|
||||
{ sgml_nomem();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wcscpy(copy, in);
|
||||
if ( ring[ringp] )
|
||||
sgml_free(ring[ringp]);
|
||||
ring[ringp++] = copy;
|
||||
if ( ringp == RINGSIZE )
|
||||
ringp = 0;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ringallo(size_t size)
|
||||
{ char *result = sgml_malloc(size);
|
||||
|
||||
if ( ring[ringp] )
|
||||
sgml_free(ring[ringp]);
|
||||
ring[ringp++] = result;
|
||||
if ( ringp == RINGSIZE )
|
||||
ringp = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* MISC *
|
||||
*******************************/
|
||||
|
||||
wchar_t const *
|
||||
str_summary(wchar_t const *s, int len)
|
||||
{ wchar_t *buf;
|
||||
size_t l = wcslen(s);
|
||||
|
||||
if ( l < (size_t)len )
|
||||
return s;
|
||||
buf = ringallo((len + 10)*sizeof(wchar_t));
|
||||
wcsncpy(buf, s, len-5);
|
||||
wcscpy(&buf[len-5], L" ... ");
|
||||
wcscpy(&buf[len], &s[l-5]);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
wchar_t *
|
||||
utf8towcs(const char *in)
|
||||
{ size_t sl = strlen(in);
|
||||
size_t len = utf8_strlen(in, sl);
|
||||
wchar_t *buf = sgml_malloc((len + 1)*sizeof(wchar_t));
|
||||
const char *e = in+sl;
|
||||
int i;
|
||||
|
||||
for(i=0; in < e;)
|
||||
{ int chr;
|
||||
|
||||
in = utf8_get_char(in, &chr);
|
||||
buf[i++] = chr;
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
wcstoutf8(const wchar_t *in)
|
||||
{ size_t size = 0;
|
||||
const wchar_t *s;
|
||||
char *rc, *o;
|
||||
|
||||
for(s=in; *s; s++)
|
||||
{ char buf[6];
|
||||
|
||||
if ( *s >= 0x80 )
|
||||
{ char *o2 = utf8_put_char(buf, *s);
|
||||
size += o2-buf;
|
||||
} else
|
||||
{ size++;
|
||||
}
|
||||
}
|
||||
|
||||
rc = sgml_malloc(size+1);
|
||||
for(o=rc, s=in; *s; s++)
|
||||
{ o = utf8_put_char(o, *s);
|
||||
}
|
||||
*o = '\0';
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* FILES *
|
||||
*******************************/
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Load a file into memory. This would be so easy if we didn't had to deal
|
||||
with &#RE/&#RS handling that forces us to create the proper record start
|
||||
and end.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
FILE *
|
||||
wfopen(const wchar_t *name, const char *mode)
|
||||
{ size_t mbl = wcstombs(NULL, name, 0);
|
||||
|
||||
if ( mbl > 0 )
|
||||
{ char *mbs = sgml_malloc(mbl+1);
|
||||
FILE *f;
|
||||
|
||||
wcstombs(mbs, name, mbl+1);
|
||||
f = fopen(mbs, mode);
|
||||
sgml_free(mbs);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
wopen(const wchar_t *name, int flags)
|
||||
{ size_t mbl = wcstombs(NULL, name, 0);
|
||||
|
||||
if ( mbl > 0 )
|
||||
{ char *mbs = sgml_malloc(mbl+1);
|
||||
int fd;
|
||||
|
||||
wcstombs(mbs, name, mbl+1);
|
||||
fd = open(mbs, flags);
|
||||
sgml_free(mbs);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ichar *
|
||||
load_sgml_file_to_charp(const ichar *file, int normalise_rsre, size_t *length)
|
||||
{ int fd;
|
||||
|
||||
if ( (fd = wopen(file, O_RDONLY|O_BINARY)) >= 0 )
|
||||
{ struct stat buf;
|
||||
|
||||
if ( fstat(fd, &buf) == 0 )
|
||||
{ size_t len = buf.st_size;
|
||||
char *r = sgml_malloc(len+1);
|
||||
|
||||
if ( r )
|
||||
{ char *s = r;
|
||||
|
||||
while(len>0)
|
||||
{ int n;
|
||||
|
||||
if ( (n=(int)read(fd, s, (unsigned int)len)) < 0 )
|
||||
{ close(fd); /* I/O error */
|
||||
sgml_free(r);
|
||||
return NULL;
|
||||
} else if ( n == 0 )
|
||||
break;
|
||||
len -= n;
|
||||
s += n;
|
||||
}
|
||||
|
||||
len = s-r;
|
||||
*s = '\0'; /* ensure closing EOS */
|
||||
close(fd);
|
||||
|
||||
{ int nl;
|
||||
int last_is_lf;
|
||||
ichar *r2, *t;
|
||||
|
||||
if ( normalise_rsre )
|
||||
{ last_is_lf = (len > 0 && s[-1] == '\n');
|
||||
for(s=r, nl=0; *s; s++)
|
||||
{ if ( *s == '\n' && s>r && s[-1] != '\r' )
|
||||
nl++;
|
||||
}
|
||||
} else
|
||||
{ nl = 0;
|
||||
last_is_lf = 0;
|
||||
}
|
||||
|
||||
r2 = sgml_malloc((len+nl+1)*sizeof(ichar));
|
||||
for(s=r, t=r2; *s; s++)
|
||||
{ if ( *s == '\n' )
|
||||
{ if ( s>r && s[-1] != '\r' )
|
||||
*t++ = CR;
|
||||
*t++ = LF;
|
||||
} else
|
||||
*t++ = *s;
|
||||
}
|
||||
len = t-r2;
|
||||
*t = '\0';
|
||||
|
||||
if ( last_is_lf )
|
||||
r2[--len] = '\0'; /* delete last LF */
|
||||
|
||||
if ( length )
|
||||
*length = len;
|
||||
sgml_free(r);
|
||||
return r2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* ALLOCATION *
|
||||
*******************************/
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
void
|
||||
sgml_nomem()
|
||||
{ fprintf(stderr, "SGML: Fatal: out of memory\n");
|
||||
|
||||
#ifdef _WINDOWS
|
||||
MessageBox(NULL, "SGML: Fatal: out of memory", "SGML", MB_OK|MB_TASKMODAL);
|
||||
#endif
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
sgml_malloc(size_t size)
|
||||
{ void *mem;
|
||||
|
||||
if ( size == 0 )
|
||||
return NULL;
|
||||
|
||||
if ( (mem = malloc(size)) )
|
||||
return mem;
|
||||
|
||||
sgml_nomem();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
sgml_realloc(void *old, size_t size)
|
||||
{ void *mem;
|
||||
|
||||
if ( old )
|
||||
{ if ( (mem = realloc(old, size)) )
|
||||
return mem;
|
||||
} else
|
||||
{ if ( (mem = malloc(size)) )
|
||||
return mem;
|
||||
}
|
||||
|
||||
sgml_nomem();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
sgml_calloc(size_t n, size_t size)
|
||||
{ void *mem;
|
||||
|
||||
if ( (mem=calloc(n, size)) )
|
||||
return mem;
|
||||
|
||||
sgml_nomem();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sgml_free(void *mem)
|
||||
{ if ( mem )
|
||||
free(mem);
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* DEBUG *
|
||||
*******************************/
|
||||
|
||||
void
|
||||
wputs(ichar *s)
|
||||
{ fwprintf(stderr, L"%ls", s);
|
||||
}
|
Reference in New Issue
Block a user