diff options
author | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
commit | ad547a6b5986815fda458221149728d9d9ab1d87 (patch) | |
tree | 16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/dvipdfm-x/dpxutil.c | |
parent | 947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff) |
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvipdfm-x/dpxutil.c')
-rw-r--r-- | Build/source/texk/dvipdfm-x/dpxutil.c | 893 |
1 files changed, 893 insertions, 0 deletions
diff --git a/Build/source/texk/dvipdfm-x/dpxutil.c b/Build/source/texk/dvipdfm-x/dpxutil.c new file mode 100644 index 00000000000..379fb515058 --- /dev/null +++ b/Build/source/texk/dvipdfm-x/dpxutil.c @@ -0,0 +1,893 @@ +/* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks. + + Copyright (C) 2002-2020 by Jin-Hwan Cho and Shunsaku Hirata, + the dvipdfmx project team. + + Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "system.h" +#include "mem.h" +#include "error.h" + +#include "dpxutil.h" + +int +xtoi (char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + else if (c >= 'a' && c <= 'f') + return (c - 'W'); + else if (c >= 'A' && c <= 'F') + return (c - '7'); + else + return -1; +} + +double +min4 (double x1, double x2, double x3, double x4) +{ + double v = x1; + if (x2 < v) v = x2; + if (x3 < v) v = x3; + if (x4 < v) v = x4; + return v; +} + +double +max4 (double x1, double x2, double x3, double x4) +{ + double v = x1; + if (x2 > v) v = x2; + if (x3 > v) v = x3; + if (x4 > v) v = x4; + return v; +} + +/* Duplicate from pdfparse.c */ +static void +skip_white (const char **pp, const char *endptr) +{ + while (*pp < endptr && + (**pp == ' ' || **pp == '\t' || **pp == '\f' || + **pp == '\r' || **pp == '\n' || **pp == '\0')) { + (*pp)++; + } +} + +/* This need to allow 'true' prefix for unit and length value must be divided + * by current magnification. + */ +int +dpx_util_read_length (double *vp, double mag, const char **pp, const char *endptr) +{ + char *q; + const char *p = *pp; + double v, u = 1.0; + const char *_ukeys[] = { +#define K_UNIT__PT 0 +#define K_UNIT__IN 1 +#define K_UNIT__CM 2 +#define K_UNIT__MM 3 +#define K_UNIT__BP 4 +#define K_UNIT__PC 5 +#define K_UNIT__DD 6 +#define K_UNIT__CC 7 +#define K_UNIT__SP 8 + "pt", "in", "cm", "mm", "bp", "pc", "dd", "cc", "sp", + NULL + }; + int k, error = 0; + + q = parse_float_decimal(&p, endptr); + if (!q) { + *vp = 0.0; *pp = p; + return -1; + } + + v = atof(q); + RELEASE(q); + + skip_white(&p, endptr); + q = parse_c_ident(&p, endptr); + if (q) { + char *qq = q; /* remember this for RELEASE, because q may be advanced */ + if (strlen(q) >= strlen("true") && + !memcmp(q, "true", strlen("true"))) { + u /= mag != 0.0 ? mag : 1.0; /* inverse magnify */ + q += strlen("true"); + } + if (strlen(q) == 0) { /* "true" was a separate word from the units */ + RELEASE(qq); + skip_white(&p, endptr); + qq = q = parse_c_ident(&p, endptr); + } + if (q) { + for (k = 0; _ukeys[k] && strcmp(_ukeys[k], q); k++); + switch (k) { + case K_UNIT__PT: u *= 72.0 / 72.27; break; + case K_UNIT__IN: u *= 72.0; break; + case K_UNIT__CM: u *= 72.0 / 2.54 ; break; + case K_UNIT__MM: u *= 72.0 / 25.4 ; break; + case K_UNIT__BP: u *= 1.0 ; break; + case K_UNIT__PC: u *= 12.0 * 72.0 / 72.27 ; break; + case K_UNIT__DD: u *= 1238.0 / 1157.0 * 72.0 / 72.27 ; break; + case K_UNIT__CC: u *= 12.0 * 1238.0 / 1157.0 * 72.0 / 72.27 ; break; + case K_UNIT__SP: u *= 72.0 / (72.27 * 65536) ; break; + default: + WARN("Unknown unit of measure: %s", q); + error = -1; + break; + } + RELEASE(qq); + } + else { + WARN("Missing unit of measure after \"true\""); + error = -1; + } + } + + *vp = v * u; *pp = p; + return error; +} + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +/* If an environment variable SOURCE_DATE_EPOCH is correctly defined like + * SOURCE_DATE_EPOCH=1456304492, then returns this value, to be used as the + * 'current time', otherwise returns INVALID_EPOCH_VALUE (= (time_t)-1). + * In the case of Microsoft Visual Studio 2010, the value should be less + * than 32535291600. + */ + +time_t +dpx_util_get_unique_time_if_given(void) +{ + const char *source_date_epoch; + int64_t epoch; + char *endptr; + time_t ret = INVALID_EPOCH_VALUE; + + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + epoch = strtoll(source_date_epoch, &endptr, 10); + if (!(epoch < 0 || *endptr != '\0' || errno != 0)) { + ret = (time_t) epoch; +#if defined(_MSC_VER) + if (ret > 32535291599ULL) + ret = 32535291599ULL; +#endif + } + } + return ret; +} + + +#ifndef HAVE_TM_GMTOFF +#ifndef HAVE_TIMEZONE + +/* auxiliary function to compute timezone offset on + systems that do not support the tm_gmtoff in struct tm, + or have a timezone variable. Such as i386-solaris. */ + +static int32_t +compute_timezone_offset() +{ + time_t now; + struct tm tm; + struct tm local; + time_t gmtoff; + + now = get_unique_time_if_given(); + if (now == INVALID_EPOCH_VALUE) { + now = time(NULL); + localtime_r(&now, &local); + gmtime_r(&now, &tm); + return (mktime(&local) - mktime(&tm)); + } else { + return(0); + } +} + +#endif /* HAVE_TIMEZONE */ +#endif /* HAVE_TM_GMTOFF */ + +/* + * Docinfo + */ +int +dpx_util_format_asn_date (char *date_string, int need_timezone) +{ + int32_t tz_offset; + time_t current_time; + struct tm *bd_time; + + current_time = dpx_util_get_unique_time_if_given(); + if (current_time == INVALID_EPOCH_VALUE) { + time(¤t_time); + bd_time = localtime(¤t_time); + +#ifdef HAVE_TM_GMTOFF + tz_offset = bd_time->tm_gmtoff; +#else +# ifdef HAVE_TIMEZONE + tz_offset = -timezone; +# else + tz_offset = compute_timezone_offset(); +# endif /* HAVE_TIMEZONE */ +#endif /* HAVE_TM_GMTOFF */ + } else { + bd_time = gmtime(¤t_time); + tz_offset = 0; + } + if (need_timezone) { + if (bd_time->tm_isdst > 0) { + tz_offset += 3600; + } + sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d%c%02d'%02d'", + bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, + bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec, + (tz_offset > 0) ? '+' : '-', abs(tz_offset) / 3600, + (abs(tz_offset) / 60) % 60); + } else { + sprintf(date_string, "D:%04d%02d%02d%02d%02d%02d", + bd_time->tm_year + 1900, bd_time->tm_mon + 1, bd_time->tm_mday, + bd_time->tm_hour, bd_time->tm_min, bd_time->tm_sec); + } + + return strlen(date_string); +} + +void +skip_white_spaces (unsigned char **s, unsigned char *endptr) +{ + while (*s < endptr) + if (!is_space(**s)) + break; + else + (*s)++; +} + +void +dpx_stack_init (dpx_stack *stack) +{ + stack->size = 0; + stack->top = NULL; + stack->bottom = NULL; +} + +void +dpx_stack_push (dpx_stack *stack, void *data) +{ + stack_elem *elem; + + ASSERT(stack); + + elem = NEW(1, stack_elem); + elem->prev = stack->top; + elem->data = data; + + stack->top = elem; + if (stack->size == 0) + stack->bottom = elem; + + stack->size++; + + return; +} + +void * +dpx_stack_pop (dpx_stack *stack) +{ + stack_elem *elem; + void *data; + + ASSERT(stack); + + if (stack->size == 0) + return NULL; + + data = stack->top->data; + elem = stack->top; + stack->top = elem->prev; + if (stack->size == 1) + stack->bottom = NULL; + RELEASE(elem); + + stack->size--; + + return data; +} + +void * +dpx_stack_top (dpx_stack *stack) +{ + void *data; + + ASSERT(stack); + + if (stack->size == 0) + return NULL; + + data = stack->top->data; + + return data; +} + +void * +dpx_stack_at (dpx_stack *stack, int pos) +{ + void *data = NULL; + stack_elem *elem; + + if (stack->size == 0) + return NULL; + + elem = stack->top; + while (pos > 0) { + elem = elem->prev; + pos--; + } + if (elem) + data = elem->data; + + return data; +} + +void +dpx_stack_roll (dpx_stack *stack, int n, int j) +{ + if (n > stack->size) + return; + if (n == 1) + return; + j = j % n; + if (j < 0) + j = n + j; + while (j-- > 0) { + int m = n; + stack_elem *elem, *prev, *top; + + elem = top = stack->top; + while (--m > 0) { + elem = elem->prev; + } + prev = elem->prev; + stack->top = top->prev; + elem->prev = top; + top->prev = prev; + } +} + +int +dpx_stack_depth (dpx_stack *stack) +{ + ASSERT(stack); + + return stack->size; +} + +void +ht_init_table (struct ht_table *ht, hval_free_func hval_free_fn) +{ + int i; + + ASSERT(ht); + + for (i = 0; i < HASH_TABLE_SIZE; i++) { + ht->table[i] = NULL; + } + ht->count = 0; + ht->hval_free_fn = hval_free_fn; +} + +void +ht_clear_table (struct ht_table *ht) +{ + int i; + + ASSERT(ht); + + for (i = 0; i < HASH_TABLE_SIZE; i++) { + struct ht_entry *hent, *next; + + hent = ht->table[i]; + while (hent) { + if (hent->value && ht->hval_free_fn) { + ht->hval_free_fn(hent->value); + } + hent->value = NULL; + if (hent->key) { + RELEASE(hent->key); + } + hent->key = NULL; + next = hent->next; + RELEASE(hent); + hent = next; + } + ht->table[i] = NULL; + } + ht->count = 0; + ht->hval_free_fn = NULL; +} + +int ht_table_size (struct ht_table *ht) +{ + ASSERT(ht); + + return ht->count; +} + +static unsigned int +get_hash (const void *key, int keylen) +{ + unsigned int hkey = 0; + int i; + + for (i = 0; i < keylen; i++) { + hkey = (hkey << 5) + hkey + ((const char *)key)[i]; + } + + return (hkey % HASH_TABLE_SIZE); +} + +void * +ht_lookup_table (struct ht_table *ht, const void *key, int keylen) +{ + struct ht_entry *hent; + unsigned int hkey; + + ASSERT(ht && key); + + hkey = get_hash(key, keylen); + hent = ht->table[hkey]; + while (hent) { + if (hent->keylen == keylen && + !memcmp(hent->key, key, keylen)) { + return hent->value; + } + hent = hent->next; + } + + return NULL; +} + +int +ht_remove_table (struct ht_table *ht, + const void *key, int keylen) +/* returns 1 if the element was found and removed and 0 otherwise */ +{ + struct ht_entry *hent, *prev; + unsigned int hkey; + + ASSERT(ht && key); + + hkey = get_hash(key, keylen); + hent = ht->table[hkey]; + prev = NULL; + while (hent) { + if (hent->keylen == keylen && + !memcmp(hent->key, key, keylen)) { + break; + } + prev = hent; + hent = hent->next; + } + if (hent) { + if (hent->key) + RELEASE(hent->key); + hent->key = NULL; + hent->keylen = 0; + if (hent->value && ht->hval_free_fn) { + ht->hval_free_fn(hent->value); + } + hent->value = NULL; + if (prev) { + prev->next = hent->next; + } else { + ht->table[hkey] = hent->next; + } + RELEASE(hent); + ht->count--; + return 1; + } else + return 0; +} + +/* replace... */ +void +ht_insert_table (struct ht_table *ht, + const void *key, int keylen, void *value) +{ + struct ht_entry *hent, *prev; + unsigned int hkey; + + ASSERT(ht && key); + + hkey = get_hash(key, keylen); + hent = ht->table[hkey]; + prev = NULL; + while (hent) { + if (hent->keylen == keylen && + !memcmp(hent->key, key, keylen)) { + break; + } + prev = hent; + hent = hent->next; + } + if (hent) { + if (hent->value && ht->hval_free_fn) + ht->hval_free_fn(hent->value); + hent->value = value; + } else { + hent = NEW(1, struct ht_entry); + hent->key = NEW(keylen, char); + memcpy(hent->key, key, keylen); + hent->keylen = keylen; + hent->value = value; + hent->next = NULL; + if (prev) { + prev->next = hent; + } else { + ht->table[hkey] = hent; + } + ht->count++; + } +} + +void +ht_append_table (struct ht_table *ht, + const void *key, int keylen, void *value) +{ + struct ht_entry *hent, *last; + unsigned int hkey; + + hkey = get_hash(key, keylen); + hent = ht->table[hkey]; + if (!hent) { + hent = NEW(1, struct ht_entry); + ht->table[hkey] = hent; + } else { + while (hent) { + last = hent; + hent = hent->next; + } + hent = NEW(1, struct ht_entry); + last->next = hent; + } + hent->key = NEW(keylen, char); + memcpy(hent->key, key, keylen); + hent->keylen = keylen; + hent->value = value; + hent->next = NULL; + + ht->count++; +} + +int +ht_set_iter (struct ht_table *ht, struct ht_iter *iter) +{ + int i; + + ASSERT(ht && iter); + + for (i = 0; i < HASH_TABLE_SIZE; i++) { + if (ht->table[i]) { + iter->index = i; + iter->curr = ht->table[i]; + iter->hash = ht; + return 0; + } + } + + return -1; +} + +void +ht_clear_iter (struct ht_iter *iter) +{ + if (iter) { + iter->index = HASH_TABLE_SIZE; + iter->curr = NULL; + iter->hash = NULL; + } +} + +char * +ht_iter_getkey (struct ht_iter *iter, int *keylen) +{ + struct ht_entry *hent; + + hent = (struct ht_entry *) iter->curr; + if (iter && hent) { + *keylen = hent->keylen; + return hent->key; + } else { + *keylen = 0; + return NULL; + } +} + +void * +ht_iter_getval (struct ht_iter *iter) +{ + struct ht_entry *hent; + + hent = (struct ht_entry *) iter->curr; + if (iter && hent) { + return hent->value; + } else { + return NULL; + } +} + +int +ht_iter_next (struct ht_iter *iter) +{ + struct ht_entry *hent; + struct ht_table *ht; + + ASSERT(iter); + + ht = iter->hash; + hent = (struct ht_entry *) iter->curr; + hent = hent->next; + while (!hent && + ++iter->index < HASH_TABLE_SIZE) { + hent = ht->table[iter->index]; + } + iter->curr = hent; + + return (hent ? 0 : -1); +} + + +static int +read_c_escchar (char *r, const char **pp, const char *endptr) +{ + int c = 0, l = 1; + const char *p = *pp; + + switch (p[0]) { + case 'a' : c = '\a'; p++; break; + case 'b' : c = '\b'; p++; break; + case 'f' : c = '\f'; p++; break; + case 'n' : c = '\n'; p++; break; + case 'r' : c = '\r'; p++; break; + case 't' : c = '\t'; p++; break; + case 'v' : c = '\v'; p++; break; + case '\\': case '?': case '\'': case '\"': + c = p[0]; p++; + break; + case '\n': l = 0; p++; break; + case '\r': + { + p++; + if (p < endptr && p[0] == '\n') + p++; + l = 0; + } + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + { + int i; + for (c = 0, i = 0; + i < 3 && p < endptr && + p[0] >= '0' && p[0] <= '7'; i++, p++) + c = (c << 3) + (p[0] - '0'); + } + break; + case 'x': + { + int i; + for (c = 0, i = 0, p++; + i < 2 && p < endptr && isxdigit((unsigned char)p[0]); + i++, p++) + c = (c << 4) + + (isdigit((unsigned char)p[0]) ? + p[0] - '0' : + (islower((unsigned char)p[0]) ? p[0] - 'a' + 10: p[0] - 'A' + 10)); + } + break; + default: + WARN("Unknown escape char sequence: \\%c", p[0]); + l = 0; p++; + break; + } + + if (r) + *r = (char) c; + *pp = p; + return l; +} + +#define C_QUOTE '"' +#define C_ESCAPE '\\' +static int +read_c_litstrc (char *q, int len, const char **pp, const char *endptr) +{ + const char *p; + int l = 0; +#define Q_TERM 0 +#define Q_CONT -1 +#define Q_ERROR_UNTERM -1 +#define Q_ERROR_INVAL -2 +#define Q_ERROR_BUFF -3 + int s = Q_CONT; + + for (l = 0, p = *pp; + s == Q_CONT && p < endptr; ) { + switch (p[0]) { + case C_QUOTE: + s = Q_TERM; p++; + break; + case C_ESCAPE: + if (q && l == len) + s = Q_ERROR_BUFF; + else { + p++; + l += read_c_escchar(q ? &q[l] : NULL, &p, endptr); + } + break; + case '\n': case '\r': + s = Q_ERROR_INVAL; + break; + default: + if (q && l == len) + s = Q_ERROR_BUFF; + else { + if (!q) + l++; + else + q[l++] = p[0]; + p++; + } + break; + } + } + if (s == Q_TERM) { + if (q && l == len) + s = Q_ERROR_BUFF; + else if (q) + q[l++] = '\0'; + } + + *pp = p; + return ((s == Q_TERM) ? l : s); +} + +char * +parse_c_string (const char **pp, const char *endptr) +{ + char *q = NULL; + const char *p = *pp; + int l = 0; + + if (p >= endptr || p[0] != C_QUOTE) + return NULL; + + p++; + l = read_c_litstrc(NULL, 0, &p, endptr); + if (l >= 0) { + q = NEW(l + 1, char); + p = *pp + 1; + l = read_c_litstrc(q, l + 1, &p, endptr); + } + + *pp = p; + return q; +} + +#define ISCNONDIGITS(c) ( \ + (c) == '_' || \ + ((c) >= 'a' && (c) <= 'z') || \ + ((c) >= 'A' && (c) <= 'Z') \ +) +#define ISCIDENTCHAR(c) ( \ + ISCNONDIGITS((c)) || \ + ((c) >= '0' && (c) <= '9') \ +) + +char * +parse_c_ident (const char **pp, const char *endptr) +{ + char *q = NULL; + const char *p = *pp; + int n; + + if (p >= endptr || !ISCNONDIGITS(*p)) + return NULL; + + for (n = 0; p < endptr && ISCIDENTCHAR(*p); p++, n++); + q = NEW(n + 1, char); + memcpy(q, *pp, n); q[n] = '\0'; + + *pp = p; + return q; +} + +char * +parse_float_decimal (const char **pp, const char *endptr) +{ + char *q = NULL; + const char *p = *pp; + int s = 0, n = 0; + + if (p >= endptr) + return NULL; + + if (p[0] == '+' || p[0] == '-') + p++; + + /* 1. .01 001 001E-001 */ + for (s = 0, n = 0; p < endptr && s >= 0; ) { + switch (p[0]) { + case '+': case '-': + if (s != 2) + s = -1; + else { + s = 3; p++; + } + break; + case '.': + if (s > 0) + s = -1; + else { + s = 1; p++; + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n++; p++; + break; + case 'E': case 'e': + if (n == 0 || s == 2) + s = -1; + else { + s = 2; p++; + } + break; + default: + s = -1; + break; + } + } + + if (n != 0) { + n = (int) (p - *pp); + q = NEW(n + 1, char); + memcpy(q, *pp, n); q[n] = '\0'; + } + + *pp = p; + return q; +} |