Changeset View
Changeset View
Standalone View
Standalone View
contrib/tzcode/zic.c
Show First 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | |||||
# include <sys/stat.h> | # include <sys/stat.h> | ||||
#endif | #endif | ||||
#ifdef S_IRUSR | #ifdef S_IRUSR | ||||
# define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) | # define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) | ||||
#else | #else | ||||
# define MKDIR_UMASK 0755 | # define MKDIR_UMASK 0755 | ||||
#endif | #endif | ||||
/* The minimum alignment of a type, for pre-C23 platforms. */ | /* The minimum alignment of a type, for pre-C23 platforms. | ||||
#if __STDC_VERSION__ < 201112 | The __SUNPRO_C test is because Oracle Developer Studio 12.6 lacks | ||||
<stdalign.h> even though __STDC_VERSION__ == 201112. */ | |||||
#if __STDC_VERSION__ < 201112 || defined __SUNPRO_C | |||||
# define alignof(type) offsetof(struct { char a; type b; }, b) | # define alignof(type) offsetof(struct { char a; type b; }, b) | ||||
#elif __STDC_VERSION__ < 202311 | #elif __STDC_VERSION__ < 202311 | ||||
# include <stdalign.h> | # include <stdalign.h> | ||||
#endif | #endif | ||||
/* The maximum length of a text line, including the trailing newline. */ | /* The maximum length of a text line, including the trailing newline. */ | ||||
#ifndef _POSIX2_LINE_MAX | #ifndef _POSIX2_LINE_MAX | ||||
# define _POSIX2_LINE_MAX 2048 | # define _POSIX2_LINE_MAX 2048 | ||||
▲ Show 20 Lines • Show All 377 Lines • ▼ Show 20 Lines | |||||
static zic_t trans[TZ_MAX_LEAPS]; | static zic_t trans[TZ_MAX_LEAPS]; | ||||
static zic_t corr[TZ_MAX_LEAPS]; | static zic_t corr[TZ_MAX_LEAPS]; | ||||
static char roll[TZ_MAX_LEAPS]; | static char roll[TZ_MAX_LEAPS]; | ||||
/* | /* | ||||
** Memory allocation. | ** Memory allocation. | ||||
*/ | */ | ||||
static ATTRIBUTE_NORETURN void | ATTRIBUTE_NORETURN static void | ||||
memory_exhausted(const char *msg) | memory_exhausted(const char *msg) | ||||
{ | { | ||||
fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); | fprintf(stderr, _("%s: Memory exhausted: %s\n"), progname, msg); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
static ATTRIBUTE_NORETURN void | ATTRIBUTE_NORETURN static void | ||||
size_overflow(void) | size_overflow(void) | ||||
{ | { | ||||
memory_exhausted(_("size overflow")); | memory_exhausted(_("size overflow")); | ||||
} | } | ||||
static ATTRIBUTE_REPRODUCIBLE size_t | ATTRIBUTE_REPRODUCIBLE static ptrdiff_t | ||||
size_sum(size_t a, size_t b) | size_sum(size_t a, size_t b) | ||||
{ | { | ||||
#ifdef ckd_add | #ifdef ckd_add | ||||
size_t sum; | ptrdiff_t sum; | ||||
if (!ckd_add(&sum, a, b)) | if (!ckd_add(&sum, a, b) && sum <= INDEX_MAX) | ||||
return sum; | return sum; | ||||
#else | #else | ||||
if (b <= SIZE_MAX - a) | if (a <= INDEX_MAX && b <= INDEX_MAX - a) | ||||
return a + b; | return a + b; | ||||
#endif | #endif | ||||
size_overflow(); | size_overflow(); | ||||
} | } | ||||
static ATTRIBUTE_REPRODUCIBLE size_t | ATTRIBUTE_REPRODUCIBLE static ptrdiff_t | ||||
size_product(size_t nitems, size_t itemsize) | size_product(ptrdiff_t nitems, ptrdiff_t itemsize) | ||||
{ | { | ||||
#ifdef ckd_mul | #ifdef ckd_mul | ||||
size_t product; | ptrdiff_t product; | ||||
if (!ckd_mul(&product, nitems, itemsize)) | if (!ckd_mul(&product, nitems, itemsize) && product <= INDEX_MAX) | ||||
return product; | return product; | ||||
#else | #else | ||||
if (nitems <= SIZE_MAX / itemsize) | ptrdiff_t nitems_max = INDEX_MAX / itemsize; | ||||
if (nitems <= nitems_max) | |||||
return nitems * itemsize; | return nitems * itemsize; | ||||
#endif | #endif | ||||
size_overflow(); | size_overflow(); | ||||
} | } | ||||
static ATTRIBUTE_REPRODUCIBLE size_t | ATTRIBUTE_REPRODUCIBLE static ptrdiff_t | ||||
align_to(size_t size, size_t alignment) | align_to(ptrdiff_t size, ptrdiff_t alignment) | ||||
{ | { | ||||
size_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); | size_t lo_bits = alignment - 1, sum = size_sum(size, lo_bits); | ||||
return sum & ~lo_bits; | return sum & ~lo_bits; | ||||
} | } | ||||
#if !HAVE_STRDUP | #if !HAVE_STRDUP | ||||
static char * | static char * | ||||
strdup(char const *str) | strdup(char const *str) | ||||
{ | { | ||||
char *result = malloc(strlen(str) + 1); | char *result = malloc(strlen(str) + 1); | ||||
return result ? strcpy(result, str) : result; | return result ? strcpy(result, str) : result; | ||||
} | } | ||||
#endif | #endif | ||||
static void * | static void * | ||||
memcheck(void *ptr) | memcheck(void *ptr) | ||||
{ | { | ||||
if (ptr == NULL) | if (ptr == NULL) | ||||
memory_exhausted(strerror(HAVE_MALLOC_ERRNO ? errno : ENOMEM)); | memory_exhausted(strerror(HAVE_MALLOC_ERRNO ? errno : ENOMEM)); | ||||
return ptr; | return ptr; | ||||
} | } | ||||
static void * ATTRIBUTE_MALLOC | ATTRIBUTE_MALLOC static void * | ||||
emalloc(size_t size) | emalloc(size_t size) | ||||
{ | { | ||||
return memcheck(malloc(size)); | return memcheck(malloc(size)); | ||||
} | } | ||||
static void * | static void * | ||||
erealloc(void *ptr, size_t size) | erealloc(void *ptr, size_t size) | ||||
{ | { | ||||
return memcheck(realloc(ptr, size)); | return memcheck(realloc(ptr, size)); | ||||
} | } | ||||
static char * ATTRIBUTE_MALLOC | ATTRIBUTE_MALLOC static char * | ||||
estrdup(char const *str) | estrdup(char const *str) | ||||
{ | { | ||||
return memcheck(strdup(str)); | return memcheck(strdup(str)); | ||||
} | } | ||||
static ptrdiff_t | static ptrdiff_t | ||||
grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize) | grow_nitems_alloc(ptrdiff_t *nitems_alloc, ptrdiff_t itemsize) | ||||
{ | { | ||||
ptrdiff_t addend = (*nitems_alloc >> 1) + 1; | ptrdiff_t addend = (*nitems_alloc >> 1) + 1; | ||||
#if defined ckd_add && defined ckd_mul | #if defined ckd_add && defined ckd_mul | ||||
ptrdiff_t product; | ptrdiff_t product; | ||||
if (!ckd_add(nitems_alloc, *nitems_alloc, addend) | if (!ckd_add(nitems_alloc, *nitems_alloc, addend) | ||||
&& !ckd_mul(&product, *nitems_alloc, itemsize) /* && product <= SIZE_MAX */) | && !ckd_mul(&product, *nitems_alloc, itemsize) && product <= INDEX_MAX) | ||||
return product; | return product; | ||||
#else | #else | ||||
ptrdiff_t amax = min(PTRDIFF_MAX, SIZE_MAX); | if (*nitems_alloc <= ((INDEX_MAX - 1) / 3 * 2) / itemsize) { | ||||
if (*nitems_alloc <= ((amax - 1) / 3 * 2) / itemsize) { | |||||
*nitems_alloc += addend; | *nitems_alloc += addend; | ||||
return *nitems_alloc * itemsize; | return *nitems_alloc * itemsize; | ||||
} | } | ||||
#endif | #endif | ||||
memory_exhausted(_("integer overflow")); | memory_exhausted(_("integer overflow")); | ||||
} | } | ||||
static void * | static void * | ||||
Show All 36 Lines | |||||
} | } | ||||
static void | static void | ||||
eat(int fnum, lineno num) | eat(int fnum, lineno num) | ||||
{ | { | ||||
eats(fnum, num, 0, -1); | eats(fnum, num, 0, -1); | ||||
} | } | ||||
static void ATTRIBUTE_FORMAT((printf, 1, 0)) | ATTRIBUTE_FORMAT((printf, 1, 0)) static void | ||||
verror(const char *const string, va_list args) | verror(const char *const string, va_list args) | ||||
{ | { | ||||
/* | /* | ||||
** Match the format of "cc" to allow sh users to | ** Match the format of "cc" to allow sh users to | ||||
** zic ... 2>&1 | error -t "*" -v | ** zic ... 2>&1 | error -t "*" -v | ||||
** on BSD systems. | ** on BSD systems. | ||||
*/ | */ | ||||
if (filenum) | if (filenum) | ||||
fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), | fprintf(stderr, _("\"%s\", line %"PRIdMAX": "), | ||||
filename(filenum), linenum); | filename(filenum), linenum); | ||||
vfprintf(stderr, string, args); | vfprintf(stderr, string, args); | ||||
if (rfilenum) | if (rfilenum) | ||||
fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"), | fprintf(stderr, _(" (rule from \"%s\", line %"PRIdMAX")"), | ||||
filename(rfilenum), rlinenum); | filename(rfilenum), rlinenum); | ||||
fprintf(stderr, "\n"); | fprintf(stderr, "\n"); | ||||
} | } | ||||
static void ATTRIBUTE_FORMAT((printf, 1, 2)) | ATTRIBUTE_FORMAT((printf, 1, 2)) static void | ||||
error(const char *const string, ...) | error(const char *const string, ...) | ||||
{ | { | ||||
va_list args; | va_list args; | ||||
va_start(args, string); | va_start(args, string); | ||||
verror(string, args); | verror(string, args); | ||||
va_end(args); | va_end(args); | ||||
errors = true; | errors = true; | ||||
} | } | ||||
static void ATTRIBUTE_FORMAT((printf, 1, 2)) | ATTRIBUTE_FORMAT((printf, 1, 2)) static void | ||||
warning(const char *const string, ...) | warning(const char *const string, ...) | ||||
{ | { | ||||
va_list args; | va_list args; | ||||
fprintf(stderr, _("warning: ")); | fprintf(stderr, _("warning: ")); | ||||
va_start(args, string); | va_start(args, string); | ||||
verror(string, args); | verror(string, args); | ||||
va_end(args); | va_end(args); | ||||
warnings = true; | warnings = true; | ||||
Show All 13 Lines | fprintf(stderr, "%s: %s%s%s%s%s\n", progname, | ||||
name ? name : "", name ? ": " : "", | name ? name : "", name ? ": " : "", | ||||
e); | e); | ||||
if (tempname) | if (tempname) | ||||
(void)remove(tempname); | (void)remove(tempname); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
} | } | ||||
static ATTRIBUTE_NORETURN void | ATTRIBUTE_NORETURN static void | ||||
usage(FILE *stream, int status) | usage(FILE *stream, int status) | ||||
{ | { | ||||
fprintf(stream, | fprintf(stream, | ||||
_("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" | _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n" | ||||
"\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" | "\t[ -b {slim|fat} ] [ -d directory ] [ -l localtime ]" | ||||
" [ -L leapseconds ] \\\n" | " [ -L leapseconds ] \\\n" | ||||
"\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n" | "\t[ -p posixrules ] [ -r '[@lo][/@hi]' ] [ -R '@hi' ] \\\n" | ||||
"\t[ -t localtime-link ] [ -D ] [ -g gid ] [ -u uid ] \\\n" | "\t[ -t localtime-link ] [ -D ] [ -g gid ] [ -u uid ] \\\n" | ||||
▲ Show 20 Lines • Show All 752 Lines • ▼ Show 20 Lines | |||||
/* Create symlink contents suitable for symlinking FROM to TO, as a | /* Create symlink contents suitable for symlinking FROM to TO, as a | ||||
freshly allocated string. FROM should be a relative file name, and | freshly allocated string. FROM should be a relative file name, and | ||||
is relative to the global variable DIRECTORY. TO can be either | is relative to the global variable DIRECTORY. TO can be either | ||||
relative or absolute. */ | relative or absolute. */ | ||||
static char * | static char * | ||||
relname(char const *target, char const *linkname) | relname(char const *target, char const *linkname) | ||||
{ | { | ||||
size_t i, taillen, dir_len = 0, dotdots = 0; | size_t i, taillen, dir_len = 0, dotdots = 0; | ||||
ptrdiff_t dotdotetcsize, linksize = min(PTRDIFF_MAX, SIZE_MAX); | ptrdiff_t dotdotetcsize, linksize = INDEX_MAX; | ||||
char const *f = target; | char const *f = target; | ||||
char *result = NULL; | char *result = NULL; | ||||
if (*linkname == '/') { | if (*linkname == '/') { | ||||
/* Make F absolute too. */ | /* Make F absolute too. */ | ||||
size_t len = strlen(directory); | size_t len = strlen(directory); | ||||
size_t lenslash = len + (len && directory[len - 1] != '/'); | size_t lenslash = len + (len && directory[len - 1] != '/'); | ||||
size_t targetsize = strlen(target) + 1; | size_t targetsize = strlen(target) + 1; | ||||
linksize = size_sum(lenslash, targetsize); | linksize = size_sum(lenslash, targetsize); | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | if (strcmp(name, "-") == 0) { | ||||
fprintf(stderr, _("%s: Can't open %s: %s\n"), | fprintf(stderr, _("%s: Can't open %s: %s\n"), | ||||
progname, name, e); | progname, name, e); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
wantcont = false; | wantcont = false; | ||||
for (num = 1; ; ++num) { | for (num = 1; ; ++num) { | ||||
enum { bufsize_bound | enum { bufsize_bound | ||||
= (min(INT_MAX, min(PTRDIFF_MAX, SIZE_MAX)) | = (min(INT_MAX, INDEX_MAX) / FORMAT_LEN_GROWTH_BOUND) }; | ||||
/ FORMAT_LEN_GROWTH_BOUND) }; | |||||
char buf[min(_POSIX2_LINE_MAX, bufsize_bound)]; | char buf[min(_POSIX2_LINE_MAX, bufsize_bound)]; | ||||
int nfields; | int nfields; | ||||
char *fields[MAX_FIELDS]; | char *fields[MAX_FIELDS]; | ||||
eat(fnum, num); | eat(fnum, num); | ||||
if (!inputline(fp, buf, sizeof buf)) | if (!inputline(fp, buf, sizeof buf)) | ||||
break; | break; | ||||
nfields = getfields(buf, fields, | nfields = getfields(buf, fields, | ||||
sizeof fields / sizeof *fields); | sizeof fields / sizeof *fields); | ||||
▲ Show 20 Lines • Show All 1,919 Lines • ▼ Show 20 Lines | switch (a) { | ||||
case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; | case 'P': return 'p'; case 'Q': return 'q'; case 'R': return 'r'; | ||||
case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; | case 'S': return 's'; case 'T': return 't'; case 'U': return 'u'; | ||||
case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; | case 'V': return 'v'; case 'W': return 'w'; case 'X': return 'x'; | ||||
case 'Y': return 'y'; case 'Z': return 'z'; | case 'Y': return 'y'; case 'Z': return 'z'; | ||||
} | } | ||||
} | } | ||||
/* case-insensitive equality */ | /* case-insensitive equality */ | ||||
static ATTRIBUTE_REPRODUCIBLE bool | ATTRIBUTE_REPRODUCIBLE static bool | ||||
ciequal(register const char *ap, register const char *bp) | ciequal(register const char *ap, register const char *bp) | ||||
{ | { | ||||
while (lowerit(*ap) == lowerit(*bp++)) | while (lowerit(*ap) == lowerit(*bp++)) | ||||
if (*ap++ == '\0') | if (*ap++ == '\0') | ||||
return true; | return true; | ||||
return false; | return false; | ||||
} | } | ||||
static ATTRIBUTE_REPRODUCIBLE bool | ATTRIBUTE_REPRODUCIBLE static bool | ||||
itsabbr(register const char *abbr, register const char *word) | itsabbr(register const char *abbr, register const char *word) | ||||
{ | { | ||||
if (lowerit(*abbr) != lowerit(*word)) | if (lowerit(*abbr) != lowerit(*word)) | ||||
return false; | return false; | ||||
++word; | ++word; | ||||
while (*++abbr != '\0') | while (*++abbr != '\0') | ||||
do { | do { | ||||
if (*word == '\0') | if (*word == '\0') | ||||
return false; | return false; | ||||
} while (lowerit(*word++) != lowerit(*abbr)); | } while (lowerit(*word++) != lowerit(*abbr)); | ||||
return true; | return true; | ||||
} | } | ||||
/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ | /* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ | ||||
static ATTRIBUTE_REPRODUCIBLE bool | ATTRIBUTE_REPRODUCIBLE static bool | ||||
ciprefix(char const *abbr, char const *word) | ciprefix(char const *abbr, char const *word) | ||||
{ | { | ||||
do | do | ||||
if (!*abbr) | if (!*abbr) | ||||
return true; | return true; | ||||
while (lowerit(*abbr++) == lowerit(*word++)); | while (lowerit(*abbr++) == lowerit(*word++)); | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | if (nsubs == arrayelts) { | ||||
error(_("Too many input fields")); | error(_("Too many input fields")); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1); | array[nsubs++] = dstart + (*dstart == '-' && dp == dstart + 1); | ||||
} | } | ||||
return nsubs; | return nsubs; | ||||
} | } | ||||
static ATTRIBUTE_NORETURN void | ATTRIBUTE_NORETURN static void | ||||
time_overflow(void) | time_overflow(void) | ||||
{ | { | ||||
error(_("time overflow")); | error(_("time overflow")); | ||||
exit(EXIT_FAILURE); | exit(EXIT_FAILURE); | ||||
} | } | ||||
static ATTRIBUTE_REPRODUCIBLE zic_t | ATTRIBUTE_REPRODUCIBLE static zic_t | ||||
oadd(zic_t t1, zic_t t2) | oadd(zic_t t1, zic_t t2) | ||||
{ | { | ||||
#ifdef ckd_add | #ifdef ckd_add | ||||
zic_t sum; | zic_t sum; | ||||
if (!ckd_add(&sum, t1, t2)) | if (!ckd_add(&sum, t1, t2)) | ||||
return sum; | return sum; | ||||
#else | #else | ||||
if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1) | if (t1 < 0 ? ZIC_MIN - t1 <= t2 : t2 <= ZIC_MAX - t1) | ||||
return t1 + t2; | return t1 + t2; | ||||
#endif | #endif | ||||
time_overflow(); | time_overflow(); | ||||
} | } | ||||
static ATTRIBUTE_REPRODUCIBLE zic_t | ATTRIBUTE_REPRODUCIBLE static zic_t | ||||
tadd(zic_t t1, zic_t t2) | tadd(zic_t t1, zic_t t2) | ||||
{ | { | ||||
#ifdef ckd_add | #ifdef ckd_add | ||||
zic_t sum; | zic_t sum; | ||||
if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time) | if (!ckd_add(&sum, t1, t2) && min_time <= sum && sum <= max_time) | ||||
return sum; | return sum; | ||||
#else | #else | ||||
if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1) | if (t1 < 0 ? min_time - t1 <= t2 : t2 <= max_time - t1) | ||||
▲ Show 20 Lines • Show All 242 Lines • Show Last 20 Lines |