SWI i/O lib

This commit is contained in:
Vítor Santos Costa 2015-06-19 01:13:46 +01:00
parent 0889596e8b
commit 0552edce2c
29 changed files with 1049 additions and 0 deletions

View File

@ -0,0 +1,37 @@
################################################################
# Makefile for libtai
#
# Author: Jan Wielemaker
# E-mail: wielemak@science.uva.nl
################################################################
!include ..\rules.mk
LIBOBJ= tai_add.obj tai_now.obj tai_pack.obj tai_sub.obj \
tai_unpack.obj taia_add.obj taia_approx.obj \
taia_fmtfrac.obj taia_frac.obj taia_half.obj taia_less.obj \
taia_now.obj taia_pack.obj taia_sub.obj taia_tai.obj \
taia_unpack.obj caldate_fmt.obj caldate_scan.obj \
caldate_fmjd.obj caldate_mjd.obj caldate_norm.obj \
caldate_ster.obj leapsecs_read.obj \
leapsecs_init.obj leapsecs_add.obj leapsecs_sub.obj \
caltime_fmt.obj caltime_scan.obj caltime_tai.obj \
caltime_utc.obj
all: tai.lib
tai.lib: $(LIBOBJ)
if exist $@ del $@
$(AR) /out:$@ /nologo $(LIBOBJ)
################################################################
# Cleanup
################################################################
clean::
if exist *.obj del *.obj
if exist *~ del *~
distclean: clean
-del tai.lib *.pdb 2>nul

View File

@ -0,0 +1,10 @@
libtai 0.60, alpha.
19981013
Copyright 1998
D. J. Bernstein, djb@pobox.com
http://pobox.com/~djb/libtai.html
libtai is a library for storing and manipulating dates and times. See
BLURB for a more detailed advertisement.
INSTALL says how to set up and test libtai.

View File

View File

@ -0,0 +1,6 @@
test caldate_mjd handling of weird days
test caldate_mjd handling of weird months
manually verify check.out
make 32-bit version?
test, test, test!
support time zones

View File

@ -0,0 +1 @@
libtai 0.60

View File

@ -0,0 +1,39 @@
#include <stdio.h>
#include <stdlib.h>
#include "tai.h"
#include "leapsecs.h"
#include "taia.h"
#include "caltime.h"
struct taia now;
struct tai sec;
struct caltime ct;
char x[TAIA_FMTFRAC];
int
main(int argc, char **argv)
{
if (leapsecs_init() == -1) {
fprintf(stderr,"utcnow: fatal: unable to init leapsecs\n");
exit(111);
}
taia_now(&now);
x[taia_fmtfrac(x,&now)] = 0;
taia_tai(&now,&sec);
caltime_utc(&ct,&sec,(int *) 0,(int *) 0);
printf("%ld-%02d-%02d %02d:%02d:%02d.%s\n"
,ct.date.year
,ct.date.month
,ct.date.day
,ct.hour
,ct.minute
,ct.second
,x
);
exit(0);
}

View File

@ -0,0 +1,83 @@
.TH tai 3
.SH NAME
tai \- manipulate times with 1-second precision
.SH SYNTAX
.B #include <tai.h>
double \fBtai_approx\fP(&\fIt\fR);
int \fBtai_less\fP(&\fIa\fR,&\fIb\fR);
.br
void \fBtai_add\fP(&\fIt\fR,&\fIa\fR,&\fIb\fR);
.br
void \fBtai_sub\fP(&\fIt\fR,&\fIa\fR,&\fIb\fR);
struct tai \fIt\fR;
.br
struct tai \fIa\fR;
.br
struct tai \fIb\fR;
.SH DESCRIPTION
A
.B struct tai
stores an integer between 0 inclusive and 2^64 exclusive.
The format of
.B struct tai
is designed to speed up common operations;
applications should not look inside
.B struct tai\fR.
A
.B struct tai
variable is commonly used to store
a TAI64 label.
Each TAI64 label refers to one second of real time.
TAI64 labels span a period of
hundreds of billions of years.
See
.B http://pobox.com/~djb/proto/tai64.txt
for more information.
A
.B struct tai
variable may also be used to store
the numerical difference between two TAI64 labels.
.SH ARITHMETIC
.B tai_approx
returns a double-precision approximation to
.IR t .
The result of
.B tai_approx
is always nonnegative.
.B tai_less
returns 1 if
.I a
is smaller than
.IR b ,
0 otherwise.
.B tai_add
adds
.I a
and
.I b
modulo 2^64
and puts the result into
.IR t .
The inputs and outputs may overlap.
.B tai_sub
subtracts
.I b
from
.I a
modulo 2^64
and puts the result into
.IR t .
The inputs and outputs may overlap.
.SH "SEE ALSO"
tai_now(3),
tai_pack(3),
taia(3),
utc(3)

View File

@ -0,0 +1,36 @@
#ifndef TAI_H
#define TAI_H
#ifdef __WINDOWS__
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <inttypes.h> /* more portable than stdint.h */
#endif
#if defined(__WINDOWS__) && !defined(__GNUC__)
#define LL(x) x ## i64
#define ULL(x) x ## ui64
#else
#define LL(x) x ## LL
#define ULL(x) x ## ULL
#endif
struct tai {
uint64_t x;
} ;
extern void tai_now(struct tai *t);
/* JW: MSVC cannot convert unsigned to double :-( */
#define tai_approx(t) ((double) ((int64_t)(t)->x))
extern void tai_add(struct tai *t, struct tai *u, struct tai *v);
extern void tai_sub(struct tai *t, struct tai *u, struct tai *v);
#define tai_less(t,u) ((t)->x < (u)->x)
#define TAI_PACK 8
extern void tai_pack(char *s, struct tai *t);
extern void tai_unpack(char *s, struct tai *t);
#endif

View File

@ -0,0 +1,6 @@
#include "tai.h"
void tai_add(struct tai *t, struct tai *u, struct tai *v)
{
t->x = u->x + v->x;
}

View File

@ -0,0 +1,34 @@
.TH tai_now 3
.SH NAME
tai_now \- get current time, with 1-second precision
.SH SYNTAX
.B #include <tai.h>
void \fBtai_now\fP(&\fIt\fR);
struct tai \fIt\fR;
.SH DESCRIPTION
.B tai_now
puts the current time into
.IR t .
More precisely:
.B tai_now
puts into
.I t
its best guess as to the TAI64 label for the 1-second interval
that contains the current time.
.SH NOTES
This implementation of
.B tai_now
assumes that the
.B time_t
returned from the
.B time
function
represents the number of TAI seconds since
1970-01-01 00:00:10 TAI.
.SH "SEE ALSO"
tai(3),
taia_now(3),
time(3)

View File

@ -0,0 +1,7 @@
#include <time.h>
#include "tai.h"
void tai_now(struct tai *t)
{
t->x = ULL(4611686018427387914) + (uint64_t) time((time_t *) 0);
}

View File

@ -0,0 +1,36 @@
.TH tai_pack 3
.SH NAME
tai_pack \- convert TAI64 labels to external format
.SH SYNTAX
.B #include <tai.h>
void \fBtai_pack\fP(\fIbuf\fR,&\fIt\fR);
.br
void \fBtai_unpack\fP(\fIbuf\fR,&\fIt\fR);
char \fIbuf\fR[\fBTAI_PACK\fP];
.br
struct tai \fIt\fR;
.SH DESCRIPTION
.B tai_pack
converts a TAI64 label
from internal format in
.I t
to TAI64 format in
.IR buf .
.B tai_unpack
converts a TAI64 label
from TAI64 format in
.I buf
to internal format in
.IR t .
.B TAI_PACK
is 8.
See
.B http://pobox.com/~djb/proto/tai64.txt
for more information about TAI64 format.
.SH "SEE ALSO"
tai(3)

View File

@ -0,0 +1,17 @@
#include "tai.h"
void tai_pack(char *s, struct tai *t)
{
uint64_t x;
x = t->x;
/* JW: Cast to int need to get MSVC6 silent */
s[7] = (int)x & 255; x >>= 8;
s[6] = (int)x & 255; x >>= 8;
s[5] = (int)x & 255; x >>= 8;
s[4] = (int)x & 255; x >>= 8;
s[3] = (int)x & 255; x >>= 8;
s[2] = (int)x & 255; x >>= 8;
s[1] = (int)x & 255; x >>= 8;
s[0] = (int)x;
}

View File

@ -0,0 +1,6 @@
#include "tai.h"
void tai_sub(struct tai *t, struct tai *u, struct tai *v)
{
t->x = u->x - v->x;
}

View File

@ -0,0 +1,16 @@
#include "tai.h"
void tai_unpack(char *s, struct tai *t)
{
uint64_t x;
x = (unsigned char) s[0];
x <<= 8; x += (unsigned char) s[1];
x <<= 8; x += (unsigned char) s[2];
x <<= 8; x += (unsigned char) s[3];
x <<= 8; x += (unsigned char) s[4];
x <<= 8; x += (unsigned char) s[5];
x <<= 8; x += (unsigned char) s[6];
x <<= 8; x += (unsigned char) s[7];
t->x = x;
}

View File

@ -0,0 +1,140 @@
.TH taia 3
.SH NAME
taia \- manipulate times with 1-attosecond precision
.SH SYNTAX
.B #include <taia.h>
double \fBtaia_approx\fP(&\fIt\fR);
.br
double \fBtaia_frac\fP(&\fIt\fR);
.br
void \fBtaia_tai\fP(&\fIt\fR,&\fIsec\fR);
int \fBtaia_less\fP(&\fIa\fR,&\fIb\fR);
.br
void \fBtaia_add\fP(&\fIt\fR,&\fIa\fR,&\fIb\fR);
.br
void \fBtaia_sub\fP(&\fIt\fR,&\fIa\fR,&\fIb\fR);
.br
void \fBtaia_half\fP(&\fIt\fR,&\fIa\fR);
unsigned int \fBtaia_fmtfrac\fP(\fIs\fR,&\fIt\fR);
struct taia \fIt\fR;
.br
struct taia \fIa\fR;
.br
struct taia \fIb\fR;
.br
struct tai \fIsec\fR;
.br
char *\fIs\fR;
.SH DESCRIPTION
A
.B struct taia
stores an integer between 0 inclusive and 2^64x10^18 exclusive.
The format of
.B struct taia
is designed to speed up common operations;
applications should not look inside
.B struct taia\fR.
A
.B struct taia
variable is commonly used to store
a TAI64NA label.
Each TAI64NA label refers to one attosecond of real time;
see
.B http://pobox.com/~djb/proto/tai64.txt
for more information.
The integer in the
.B struct taia
is 10^18 times the second count,
plus 10^9 times the nanosecond count,
plus the attosecond count.
A
.B struct taia
variable may also be used to store
the numerical difference between two TAI64NA labels.
.SH ARITHMETIC
.B taia_approx
returns a double-precision approximation to
.IR t /10^18.
The result of
.B taia_approx
is always nonnegative.
.B taia_tai
places into
.I sec
the integer part of
.IR t /10^18.
.B taia_frac
returns a double-precision approximation to
the fraction part of
.IR t /10^18.
The result of
.B taia_frac
is always nonnegative.
.B taia_less
returns 1 if
.I a
is smaller than
.IR b ,
0 otherwise.
.B taia_add
adds
.I a
and
.I b
modulo 2^64x10^18
and puts the result into
.IR t .
The inputs and outputs may overlap.
.B taia_sub
subtracts
.I b
from
.I a
modulo 2^64x10^18
and puts the result into
.IR t .
The inputs and outputs may overlap.
.B taia_half
divides
.I a
by 2, rounding down,
and puts the result into
.IR t .
The input and output may overlap.
.SH "FORMATTING"
.B taia_fmtfrac
prints the remainder of
.IR t /10^18,
padded to exactly 18 digits,
into the character buffer
.IR s ,
without a terminating NUL.
It returns 18, the number of characters written.
.I s
may be zero;
then
.B taia_fmtfrac
returns 18 without printing anything.
The macro
.B TAIA_FMTFRAC
is defined as 19;
this is enough space for the output of
.B taia_fmtfrac
and a terminating NUL.
.SH "SEE ALSO"
taia_now(3),
taia_pack(3),
tai(3)

View File

@ -0,0 +1,31 @@
#ifndef TAIA_H
#define TAIA_H
#include "tai.h"
struct taia {
struct tai sec;
unsigned long nano; /* 0...999999999 */
unsigned long atto; /* 0...999999999 */
} ;
extern void taia_tai(struct taia *ta, struct tai *t);
extern void taia_now(struct taia *t);
extern double taia_approx(struct taia *t);
extern double taia_frac(struct taia *t);
extern void taia_add(struct taia *t, struct taia *u, struct taia *v);
extern void taia_sub(struct taia *t, struct taia *u, struct taia *v);
extern void taia_half(struct taia *t, struct taia *u);
extern int taia_less(struct taia *t, struct taia *u);
#define TAIA_PACK 16
extern void taia_pack(char *s, struct taia *t);
extern void taia_unpack(char *s, struct taia *t);
#define TAIA_FMTFRAC 19
extern unsigned int taia_fmtfrac(char *s, struct taia *t);
#endif

View File

@ -0,0 +1,6 @@
#include "taia.h"
double taia_frac(struct taia *t)
{
return (t->atto * 0.000000001 + t->nano) * 0.000000001;
}

View File

@ -0,0 +1,12 @@
#include "taia.h"
/* XXX: breaks tai encapsulation */
void taia_half(struct taia *t, struct taia *u)
{
t->atto = u->atto >> 1;
if (u->nano & 1) t->atto += 500000000UL;
t->nano = u->nano >> 1;
if (u->sec.x & 1) t->nano += 500000000UL;
t->sec.x = u->sec.x >> 1;
}

View File

@ -0,0 +1,12 @@
#include "taia.h"
/* XXX: breaks tai encapsulation */
int taia_less(struct taia *t, struct taia *u)
{
if (t->sec.x < u->sec.x) return 1;
if (t->sec.x > u->sec.x) return 0;
if (t->nano < u->nano) return 1;
if (t->nano > u->nano) return 0;
return t->atto < u->atto;
}

View File

@ -0,0 +1,33 @@
.TH taia_now 3
.SH NAME
taia_now \- get current time, with 1-attosecond precision
.SH SYNTAX
.B #include <taia.h>
void \fBtaia_now\fP(&\fIt\fR);
struct taia \fIt\fR;
.SH DESCRIPTION
.B taia_now
puts the current time into
.IR t .
More precisely:
.B taia_now
puts into
.I t
its best guess as to the TAI64NA label for the 1-attosecond interval
that contains the current time.
.SH NOTES
This implementation of
.B tai_now
assumes that the
.B struct timeval
returned from
.B gettimeofday
represents the number of TAI seconds since
1970-01-01 00:00:10 TAI.
.SH "SEE ALSO"
gettimeofday(2),
tai_now(3),
taia(3)

View File

@ -0,0 +1,40 @@
#include <sys/types.h>
#ifdef __WINDOWS__
#define WINDOWS_LEAN_AND_MEAN 1
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include "taia.h"
/* XXX: breaks tai encapsulation */
/*-------------------------------------------------------------------------
* The Microsoft Win32 API can return the current system time in "file
* timestamp" format, which is a 64-bit value representing the number of
* 100-nanosecond ticks since {AD1601-01-01 00:00:00 Z}.
* 11644473600 is seconds offset AD1601 to AD1970
*------------------------------------------------------------------------*/
void taia_now(struct taia *t)
{
#ifdef __WINDOWS__
FILETIME ft;
int64_t cns; /* 100ns ticks */
/* Get the current system time */
GetSystemTimeAsFileTime(&ft);
/* Convert to longtime_t form */
cns = ((int64_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime;
t->sec.x = cns/10000000 - 11644473600 + ULL(4611686018427387914);
t->nano = (long)((cns % 10000000))*100;
t->atto = 0;
#else
struct timeval now;
gettimeofday(&now,(struct timezone *) 0);
t->sec.x = ULL(4611686018427387914) + (uint64_t) now.tv_sec;
t->nano = 1000 * now.tv_usec + 500;
t->atto = 0;
#endif
}

View File

@ -0,0 +1,36 @@
.TH taia_pack 3
.SH NAME
taia_pack \- convert TAI64NA labels to external format
.SH SYNTAX
.B #include <taia.h>
void \fBtaia_pack\fP(\fIbuf\fR,&\fIt\fR);
.br
void \fBtaia_unpack\fP(\fIbuf\fR,&\fIt\fR);
char \fIbuf\fR[\fBTAIA_PACK\fP];
.br
struct taia \fIt\fR;
.SH DESCRIPTION
.B taia_pack
converts a TAI64NA label
from internal format in
.I t
to TAI64NA format in
.IR buf .
.B taia_unpack
converts a TAI64NA label
from TAI64NA format in
.I buf
to internal format in
.IR t .
.B TAIA_PACK
is 16.
See
.B http://pobox.com/~djb/proto/tai64.txt
for more information about TAI64NA format.
.SH "SEE ALSO"
taia(3)

View File

@ -0,0 +1,20 @@
#include "taia.h"
void taia_pack(char *s, struct taia *t)
{
unsigned long x;
tai_pack(s,&t->sec);
s += 8;
x = t->atto;
s[7] = (int)x & 255; x >>= 8;
s[6] = (int)x & 255; x >>= 8;
s[5] = (int)x & 255; x >>= 8;
s[4] = (int)x;
x = t->nano;
s[3] = (int)x & 255; x >>= 8;
s[2] = (int)x & 255; x >>= 8;
s[1] = (int)x & 255; x >>= 8;
s[0] = (int)x;
}

View File

@ -0,0 +1,21 @@
#include "taia.h"
/* XXX: breaks tai encapsulation */
void taia_sub(struct taia *t, struct taia *u, struct taia *v)
{
unsigned long unano = u->nano;
unsigned long uatto = u->atto;
t->sec.x = u->sec.x - v->sec.x;
t->nano = unano - v->nano;
t->atto = uatto - v->atto;
if (t->atto > uatto) {
t->atto += 1000000000UL;
--t->nano;
}
if (t->nano > unano) {
t->nano += 1000000000UL;
--t->sec.x;
}
}

View File

@ -0,0 +1,6 @@
#include "taia.h"
void taia_tai(struct taia *ta, struct tai *t)
{
*t = ta->sec;
}

View File

@ -0,0 +1,20 @@
#include "taia.h"
void taia_unpack(char *s, struct taia *t)
{
unsigned long x;
tai_unpack(s,&t->sec);
s += 8;
x = (unsigned char) s[4];
x <<= 8; x += (unsigned char) s[5];
x <<= 8; x += (unsigned char) s[6];
x <<= 8; x += (unsigned char) s[7];
t->atto = x;
x = (unsigned char) s[0];
x <<= 8; x += (unsigned char) s[1];
x <<= 8; x += (unsigned char) s[2];
x <<= 8; x += (unsigned char) s[3];
t->nano = x;
}

View File

@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include "caldate.h"
char *montab[] = {
"January"
, "February"
, "March"
, "April"
, "May"
, "June"
, "July"
, "August"
, "September"
, "October"
, "November"
, "December"
} ;
int main(int argc, char **argv)
{
int year;
long daystart;
long dayend;
long day;
int weekday;
struct caldate cd;
while (*++argv) {
year = atoi(*argv);
cd.year = year;
cd.month = 1;
cd.day = 1;
daystart = caldate_mjd(&cd);
cd.year = year + 1;
dayend = caldate_mjd(&cd);
while ((daystart + 3) % 7) --daystart;
while ((dayend + 3) % 7) ++dayend;
for (day = daystart;day < dayend;++day) {
caldate_frommjd(&cd,day,&weekday,(int *) 0);
if (cd.year != year)
printf(" ");
else {
if (cd.month & 1)
if (cd.day < 10)
printf(" %d%c%d ",cd.day % 10,8,cd.day % 10);
else
printf("%d%c%d%d%c%d ",cd.day / 10,8,cd.day / 10,cd.day % 10,8,cd.day % 10);
else
printf("%2d ",cd.day);
if (weekday == 6) {
if ((cd.day >= 15) && (cd.day < 22))
printf(" %s %d\n",montab[cd.month - 1],year);
else
printf("\n");
}
}
}
printf("\n");
}
exit(0);
}

View File

@ -0,0 +1,272 @@
/* $Id$
Part of SWI-Prolog
Author: Jan Wielemaker and Anjo Anjewierden
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <string.h> /* get size_t */
#include "pl-utf8.h"
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
UTF-8 Decoding, based on http://www.cl.cam.ac.uk/~mgk25/unicode.html
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define CONT(i) ISUTF8_CB(in[i])
#define VAL(i, s) ((in[i]&0x3f) << s)
char *
_PL__utf8_get_char(const char *in, int *chr)
{ /* 2-byte, 0x80-0x7ff */
if ( (in[0]&0xe0) == 0xc0 && CONT(1) )
{ *chr = ((in[0]&0x1f) << 6)|VAL(1,0);
return (char *)in+2;
}
/* 3-byte, 0x800-0xffff */
if ( (in[0]&0xf0) == 0xe0 && CONT(1) && CONT(2) )
{ *chr = ((in[0]&0xf) << 12)|VAL(1,6)|VAL(2,0);
return (char *)in+3;
}
/* 4-byte, 0x10000-0x1FFFFF */
if ( (in[0]&0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3) )
{ *chr = ((in[0]&0x7) << 18)|VAL(1,12)|VAL(2,6)|VAL(3,0);
return (char *)in+4;
}
/* 5-byte, 0x200000-0x3FFFFFF */
if ( (in[0]&0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4) )
{ *chr = ((in[0]&0x3) << 24)|VAL(1,18)|VAL(2,12)|VAL(3,6)|VAL(4,0);
return (char *)in+5;
}
/* 6-byte, 0x400000-0x7FFFFFF */
if ( (in[0]&0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5) )
{ *chr = ((in[0]&0x1) << 30)|VAL(1,24)|VAL(2,18)|VAL(3,12)|VAL(4,6)|VAL(5,0);
return (char *)in+4;
}
*chr = *in;
return (char *)in+1;
}
unicode_type_t
_PL__utf8_type(const char *in0, size_t len)
{ /* 2-byte, 0x80-0x7ff */
int chr;
char *in = (char *) in0;
int type = S_ASCII;
while (in[0] != '\0' && in-in0 < len) {
if ( (in[0]&0xe0) == 0xc0 && CONT(1) )
{ chr = ((in[0]&0x1f) << 6)|VAL(1,0);
if (chr > 255) return S_WIDE;
if (chr > 127) type = S_LATIN;
in += 2;
break;
}
/* 3-byte, 0x800-0xffff */
if ( (in[0]&0xf0) == 0xe0 && CONT(1) && CONT(2) )
{ chr = ((in[0]&0xf) << 12)|VAL(1,6)|VAL(2,0);
if (chr > 255) return S_WIDE;
if (chr > 127) type = S_LATIN;
in += 3;
}
/* 4-byte, 0x10000-0x1FFFFF */
if ( (in[0]&0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3) )
{ chr = ((in[0]&0x7) << 18)|VAL(1,12)|VAL(2,6)|VAL(3,0);
if (chr > 255) return S_WIDE;
if (chr > 127) type = S_LATIN;
in += 4;
}
/* 5-byte, 0x200000-0x3FFFFFF */
if ( (in[0]&0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4) )
{ chr = ((in[0]&0x3) << 24)|VAL(1,18)|VAL(2,12)|VAL(3,6)|VAL(4,0);
if (chr > 255) return S_WIDE;
if (chr > 127) type = S_LATIN;
in += 5;
}
/* 6-byte, 0x400000-0x7FFFFFF */
if ( (in[0]&0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5) )
{ chr = ((in[0]&0x1) << 30)|VAL(1,24)|VAL(2,18)|VAL(3,12)|VAL(4,6)|VAL(5,0);
if (chr > 255) return S_WIDE;
if (chr > 127) type = S_LATIN;
in += 6;
}
in ++;
}
return type;
}
char *
_PL__utf8_put_char(char *out, int chr)
{ if ( chr < 0x80 )
{ *out++ = chr;
} else if ( chr < 0x800 )
{ *out++ = 0xc0|((chr>>6)&0x1f);
*out++ = 0x80|(chr&0x3f);
} else if ( chr < 0x10000 )
{ *out++ = 0xe0|((chr>>12)&0x0f);
*out++ = 0x80|((chr>>6)&0x3f);
*out++ = 0x80|(chr&0x3f);
} else if ( chr < 0x200000 )
{ *out++ = 0xf0|((chr>>18)&0x07);
*out++ = 0x80|((chr>>12)&0x3f);
*out++ = 0x80|((chr>>6)&0x3f);
*out++ = 0x80|(chr&0x3f);
} else if ( chr < 0x4000000 )
{ *out++ = 0xf8|((chr>>24)&0x03);
*out++ = 0x80|((chr>>18)&0x3f);
*out++ = 0x80|((chr>>12)&0x3f);
*out++ = 0x80|((chr>>6)&0x3f);
*out++ = 0x80|(chr&0x3f);
} else if ( (unsigned)chr < 0x80000000 )
{ *out++ = 0xfc|((chr>>30)&0x01);
*out++ = 0x80|((chr>>24)&0x3f);
*out++ = 0x80|((chr>>18)&0x3f);
*out++ = 0x80|((chr>>12)&0x3f);
*out++ = 0x80|((chr>>6)&0x3f);
*out++ = 0x80|(chr&0x3f);
}
return out;
}
char *
_PL__utf8_skip_char(const char *in)
{ /* 2-byte, 0x80-0x7ff */
if ( (in[0]&0xe0) == 0xc0 && CONT(1) )
{
return (char *)in+2;
}
/* 3-byte, 0x800-0xffff */
if ( (in[0]&0xf0) == 0xe0 && CONT(1) && CONT(2) )
{
return (char *)in+3;
}
/* 4-byte, 0x10000-0x1FFFFF */
if ( (in[0]&0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3) )
{
return (char *)in+4;
}
/* 5-byte, 0x200000-0x3FFFFFF */
if ( (in[0]&0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4) )
{
return (char *)in+5;
}
/* 6-byte, 0x400000-0x7FFFFFF */
if ( (in[0]&0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5) )
{
return (char *)in+4;
}
return (char *)in+1;
}
size_t
utf8_strlen(const char *s, size_t len)
{ const char *e = &s[len];
unsigned int l = 0;
while(s<e)
{ int chr;
s = utf8_get_char(s, &chr);
l++;
}
return l;
}
size_t
utf8_strlen1(const char *s)
{
unsigned int l = 0;
while( s [0] )
{
s = utf8_skip_char(s);
l++;
}
return l;
}
const char *
utf8_skip(const char *s, int n)
{
while(n--)
{
if (!s[0]) return NULL;
s = utf8_skip_char(s);
}
return s;
}
int
utf8_strncmp(const char *s1, const char *s2, size_t n)
{
while(n-- >0)
{ int chr1, chr2;
s1 = utf8_get_char(s1, &chr1);
s2 = utf8_get_char(s2, &chr2);
if (chr1-chr2) return chr1-chr2;
if (!chr1) return 0;
}
return 0;
}
int
utf8_strprefix(const char *s1, const char *s2)
{
while(1)
{ int chr1, chr2;
s1 = utf8_get_char(s1, &chr1);
s2 = utf8_get_char(s2, &chr2);
if (!chr2) return 1;
if (chr1-chr2) return 0;
}
return 0;
}
char *
utf8_wcscpy(char *sf, const wchar_t *s0)
{
char *sf0 = sf;
while(1)
{ int chr1;
chr1 = * s0++;
if (chr1 == '\0') {
*sf++ = '\0';
return sf0;
}
sf = utf8_put_char(sf, chr1);
}
return NULL;
}