diff options
author | ru <ru@FreeBSD.org> | 2001-04-17 12:12:05 +0000 |
---|---|---|
committer | ru <ru@FreeBSD.org> | 2001-04-17 12:12:05 +0000 |
commit | 0e0a0e6429c7113acf15c4c94bd5fe94c45f9e99 (patch) | |
tree | f3137c4283de8869ebcae1dd0fe43f590276c1dc /contrib/groff/src/libs | |
parent | a812d8b090bc4edc23150bff257717b24f282e41 (diff) | |
download | FreeBSD-src-0e0a0e6429c7113acf15c4c94bd5fe94c45f9e99.zip FreeBSD-src-0e0a0e6429c7113acf15c4c94bd5fe94c45f9e99.tar.gz |
Virgin import of FSF groff v1.17
Diffstat (limited to 'contrib/groff/src/libs')
43 files changed, 6535 insertions, 0 deletions
diff --git a/contrib/groff/src/libs/libbib/Makefile.sub b/contrib/groff/src/libs/libbib/Makefile.sub new file mode 100644 index 0000000..482f01a --- /dev/null +++ b/contrib/groff/src/libs/libbib/Makefile.sub @@ -0,0 +1,14 @@ +LIB=bib +OBJS=\ + common.o \ + index.o \ + linear.o \ + search.o \ + map.o +CCSRCS=\ + $(srcdir)/common.cc \ + $(srcdir)/index.cc \ + $(srcdir)/linear.cc \ + $(srcdir)/search.cc +CSRCS=\ + $(srcdir)/map.c diff --git a/contrib/groff/src/libs/libbib/common.cc b/contrib/groff/src/libs/libbib/common.cc new file mode 100644 index 0000000..4b2bcca --- /dev/null +++ b/contrib/groff/src/libs/libbib/common.cc @@ -0,0 +1,38 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +unsigned hash(const char *s, int len) +{ +#if 0 + unsigned h = 0, g; + while (*s != '\0') { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } +#endif + unsigned h = 0; + while (--len >= 0) + h = *s++ + 65587*h; + return h; +} + diff --git a/contrib/groff/src/libs/libbib/index.cc b/contrib/groff/src/libs/libbib/index.cc new file mode 100644 index 0000000..5573771 --- /dev/null +++ b/contrib/groff/src/libs/libbib/index.cc @@ -0,0 +1,641 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include "posix.h" +#include "lib.h" +#include "cset.h" +#include "cmap.h" +#include "errarg.h" +#include "error.h" + +#include "refid.h" +#include "search.h" +#include "index.h" +#include "defs.h" + +#include "nonposix.h" + +// Interface to mmap. +extern "C" { + void *mapread(int fd, int len); + int unmap(void *, int len); +} + +#if 0 +const +#endif +int minus_one = -1; + +int verify_flag = 0; + +struct word_list; + +class index_search_item : public search_item { + search_item *out_of_date_files; + index_header header; + char *buffer; + void *map_addr; + int map_len; + tag *tags; + int *table; + int *lists; + char *pool; + char *key_buffer; + char *filename_buffer; + int filename_buflen; + char **common_words_table; + int common_words_table_size; + const char *ignore_fields; + time_t mtime; + + const char *do_verify(); + const int *search1(const char **pp, const char *end); + const int *search(const char *ptr, int length, int **temp_listp); + const char *munge_filename(const char *); + void read_common_words_file(); + void add_out_of_date_file(int fd, const char *filename, int fid); +public: + index_search_item(const char *, int); + ~index_search_item(); + int load(int fd); + search_item_iterator *make_search_item_iterator(const char *); + int verify(); + void check_files(); + int next_filename_id() const; + friend class index_search_item_iterator; +}; + +class index_search_item_iterator : public search_item_iterator { + index_search_item *indx; + search_item_iterator *out_of_date_files_iter; + search_item *next_out_of_date_file; + const int *found_list; + int *temp_list; + char *buf; + int buflen; + linear_searcher searcher; + char *query; + int get_tag(int tagno, const linear_searcher &, const char **, int *, + reference_id *); +public: + index_search_item_iterator(index_search_item *, const char *); + ~index_search_item_iterator(); + int next(const linear_searcher &, const char **, int *, reference_id *); +}; + + +index_search_item::index_search_item(const char *filename, int fid) +: search_item(filename, fid), out_of_date_files(0), buffer(0), map_addr(0), + map_len(0), key_buffer(0), filename_buffer(0), filename_buflen(0), + common_words_table(0) +{ +} + +index_search_item::~index_search_item() +{ + if (buffer) + free(buffer); + if (map_addr) { + if (unmap(map_addr, map_len) < 0) + error("unmap: %1", strerror(errno)); + } + while (out_of_date_files) { + search_item *tem = out_of_date_files; + out_of_date_files = out_of_date_files->next; + delete tem; + } + a_delete filename_buffer; + a_delete key_buffer; + if (common_words_table) { + for (int i = 0; i < common_words_table_size; i++) + a_delete common_words_table[i]; + a_delete common_words_table; + } +} + +class file_closer { + int *fdp; +public: + file_closer(int &fd) : fdp(&fd) { } + ~file_closer() { close(*fdp); } +}; + +// Tell the compiler that a variable is intentionally unused. +inline void unused(void *) { } + +int index_search_item::load(int fd) +{ + file_closer fd_closer(fd); // close fd on return + unused(&fd_closer); + struct stat sb; + if (fstat(fd, &sb) < 0) { + error("can't fstat `%1': %2", name, strerror(errno)); + return 0; + } + if (!S_ISREG(sb.st_mode)) { + error("`%1' is not a regular file", name); + return 0; + } + mtime = sb.st_mtime; + int size = int(sb.st_size); + char *addr; + map_addr = mapread(fd, size); + if (map_addr) { + addr = (char *)map_addr; + map_len = size; + } + else { + addr = buffer = (char *)malloc(size); + if (buffer == 0) { + error("can't allocate buffer for `%1'", name); + return 0; + } + char *ptr = buffer; + int bytes_to_read = size; + while (bytes_to_read > 0) { + int nread = read(fd, ptr, bytes_to_read); + if (nread == 0) { + error("unexpected EOF on `%1'", name); + return 0; + } + if (nread < 0) { + error("read error on `%1': %2", name, strerror(errno)); + return 0; + } + bytes_to_read -= nread; + ptr += nread; + } + } + header = *(index_header *)addr; + if (header.magic != INDEX_MAGIC) { + error("`%1' is not an index file: wrong magic number", name); + return 0; + } + if (header.version != INDEX_VERSION) { + error("version number in `%1' is wrong: was %2, should be %3", + name, header.version, INDEX_VERSION); + return 0; + } + int sz = (header.tags_size * sizeof(tag) + + header.lists_size * sizeof(int) + + header.table_size * sizeof(int) + + header.strings_size + + sizeof(header)); + if (sz != size) { + error("size of `%1' is wrong: was %2, should be %3", + name, size, sz); + return 0; + } + tags = (tag *)(addr + sizeof(header)); + lists = (int *)(tags + header.tags_size); + table = (int *)(lists + header.lists_size); + pool = (char *)(table + header.table_size); + ignore_fields = strchr(strchr(pool, '\0') + 1, '\0') + 1; + key_buffer = new char[header.truncate]; + read_common_words_file(); + return 1; +} + +const char *index_search_item::do_verify() +{ + if (tags == 0) + return "not loaded"; + if (lists[header.lists_size - 1] >= 0) + return "last list element not negative"; + int i; + for (i = 0; i < header.table_size; i++) { + int li = table[i]; + if (li >= header.lists_size) + return "bad list index"; + if (li >= 0) { + for (int *ptr = lists + li; *ptr >= 0; ptr++) { + if (*ptr >= header.tags_size) + return "bad tag index"; + if (*ptr >= ptr[1] && ptr[1] >= 0) + return "list not ordered"; + } + } + } + for (i = 0; i < header.tags_size; i++) { + if (tags[i].filename_index >= header.strings_size) + return "bad index in tags"; + if (tags[i].length < 0) + return "bad length in tags"; + if (tags[i].start < 0) + return "bad start in tags"; + } + if (pool[header.strings_size - 1] != '\0') + return "last character in pool not nul"; + return 0; +} + +int index_search_item::verify() +{ + const char *reason = do_verify(); + if (!reason) + return 1; + error("`%1' is bad: %2", name, reason); + return 0; +} + +int index_search_item::next_filename_id() const +{ + return filename_id + header.strings_size + 1; +} + +search_item_iterator *index_search_item::make_search_item_iterator( + const char *query) +{ + return new index_search_item_iterator(this, query); +} + +search_item *make_index_search_item(const char *filename, int fid) +{ + char *index_filename = new char[strlen(filename) + sizeof(INDEX_SUFFIX)]; + strcpy(index_filename, filename); + strcat(index_filename, INDEX_SUFFIX); + int fd = open(index_filename, O_RDONLY | O_BINARY); + if (fd < 0) + return 0; + index_search_item *item = new index_search_item(index_filename, fid); + a_delete index_filename; + if (!item->load(fd)) { + close(fd); + delete item; + return 0; + } + else if (verify_flag && !item->verify()) { + delete item; + return 0; + } + else { + item->check_files(); + return item; + } +} + + +index_search_item_iterator::index_search_item_iterator(index_search_item *ind, + const char *q) +: indx(ind), out_of_date_files_iter(0), next_out_of_date_file(0), temp_list(0), + buf(0), buflen(0), + searcher(q, strlen(q), ind->ignore_fields, ind->header.truncate), + query(strsave(q)) +{ + found_list = indx->search(q, strlen(q), &temp_list); + if (!found_list) { + found_list = &minus_one; + warning("all keys would have been discarded in constructing index `%1'", + indx->name); + } +} + +index_search_item_iterator::~index_search_item_iterator() +{ + a_delete temp_list; + a_delete buf; + a_delete query; + delete out_of_date_files_iter; +} + +int index_search_item_iterator::next(const linear_searcher &, + const char **pp, int *lenp, + reference_id *ridp) +{ + if (found_list) { + for (;;) { + int tagno = *found_list; + if (tagno == -1) + break; + found_list++; + if (get_tag(tagno, searcher, pp, lenp, ridp)) + return 1; + } + found_list = 0; + next_out_of_date_file = indx->out_of_date_files; + } + while (next_out_of_date_file) { + if (out_of_date_files_iter == 0) + out_of_date_files_iter + = next_out_of_date_file->make_search_item_iterator(query); + if (out_of_date_files_iter->next(searcher, pp, lenp, ridp)) + return 1; + delete out_of_date_files_iter; + out_of_date_files_iter = 0; + next_out_of_date_file = next_out_of_date_file->next; + } + return 0; +} + +int index_search_item_iterator::get_tag(int tagno, + const linear_searcher &searcher, + const char **pp, int *lenp, + reference_id *ridp) +{ + if (tagno < 0 || tagno >= indx->header.tags_size) { + error("bad tag number"); + return 0; + } + tag *tp = indx->tags + tagno; + const char *filename = indx->munge_filename(indx->pool + tp->filename_index); + int fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + error("can't open `%1': %2", filename, strerror(errno)); + return 0; + } + struct stat sb; + if (fstat(fd, &sb) < 0) { + error("can't fstat: %1", strerror(errno)); + close(fd); + return 0; + } + time_t mtime = sb.st_mtime; + if (mtime > indx->mtime) { + indx->add_out_of_date_file(fd, filename, + indx->filename_id + tp->filename_index); + return 0; + } + int res = 0; + FILE *fp = fdopen(fd, FOPEN_RB); + if (!fp) { + error("fdopen failed"); + close(fd); + return 0; + } + if (tp->start != 0 && fseek(fp, long(tp->start), 0) < 0) + error("can't seek on `%1': %2", filename, strerror(errno)); + else { + int length = tp->length; + int err = 0; + if (length == 0) { + struct stat sb; + if (fstat(fileno(fp), &sb) < 0) { + error("can't stat `%1': %2", filename, strerror(errno)); + err = 1; + } + else if (!S_ISREG(sb.st_mode)) { + error("`%1' is not a regular file", filename); + err = 1; + } + else + length = int(sb.st_size); + } + if (!err) { + if (length + 2 > buflen) { + a_delete buf; + buflen = length + 2; + buf = new char[buflen]; + } + if (fread(buf + 1, 1, length, fp) != length) + error("fread on `%1' failed: %2", filename, strerror(errno)); + else { + buf[0] = '\n'; + // Remove the CR characters from CRLF pairs. + int sidx = 1, didx = 1; + for ( ; sidx < length + 1; sidx++, didx++) + { + if (buf[sidx] == '\r') + { + if (buf[++sidx] != '\n') + buf[didx++] = '\r'; + else + length--; + } + if (sidx != didx) + buf[didx] = buf[sidx]; + } + buf[length + 1] = '\n'; + res = searcher.search(buf + 1, buf + 2 + length, pp, lenp); + if (res && ridp) + *ridp = reference_id(indx->filename_id + tp->filename_index, + tp->start); + } + } + } + fclose(fp); + return res; +} + +const char *index_search_item::munge_filename(const char *filename) +{ + if (IS_ABSOLUTE(filename)) + return filename; + const char *cwd = pool; + int need_slash = (cwd[0] != 0 + && strchr(DIR_SEPS, strchr(cwd, '\0')[-1]) == 0); + int len = strlen(cwd) + strlen(filename) + need_slash + 1; + if (len > filename_buflen) { + a_delete filename_buffer; + filename_buflen = len; + filename_buffer = new char[len]; + } + strcpy(filename_buffer, cwd); + if (need_slash) + strcat(filename_buffer, "/"); + strcat(filename_buffer, filename); + return filename_buffer; +} + +const int *index_search_item::search1(const char **pp, const char *end) +{ + while (*pp < end && !csalnum(**pp)) + *pp += 1; + if (*pp >= end) + return 0; + const char *start = *pp; + while (*pp < end && csalnum(**pp)) + *pp += 1; + int len = *pp - start; + if (len < header.shortest) + return 0; + if (len > header.truncate) + len = header.truncate; + int is_number = 1; + for (int i = 0; i < len; i++) + if (csdigit(start[i])) + key_buffer[i] = start[i]; + else { + key_buffer[i] = cmlower(start[i]); + is_number = 0; + } + if (is_number && !(len == 4 && start[0] == '1' && start[1] == '9')) + return 0; + unsigned hc = hash(key_buffer, len); + if (common_words_table) { + for (int h = hc % common_words_table_size; + common_words_table[h]; + --h) { + if (strlen(common_words_table[h]) == len + && memcmp(common_words_table[h], key_buffer, len) == 0) + return 0; + if (h == 0) + h = common_words_table_size; + } + } + int li = table[int(hc % header.table_size)]; + return li < 0 ? &minus_one : lists + li; +} + +static void merge(int *result, const int *s1, const int *s2) +{ + for (; *s1 >= 0; s1++) { + while (*s2 >= 0 && *s2 < *s1) + s2++; + if (*s2 == *s1) + *result++ = *s2; + } + *result++ = -1; +} + +const int *index_search_item::search(const char *ptr, int length, + int **temp_listp) +{ + const char *end = ptr + length; + if (*temp_listp) { + a_delete *temp_listp; + *temp_listp = 0; + } + const int *first_list = 0; + while (ptr < end && (first_list = search1(&ptr, end)) == 0) + ; + if (!first_list) + return 0; + if (*first_list < 0) + return first_list; + const int *second_list = 0; + while (ptr < end && (second_list = search1(&ptr, end)) == 0) + ; + if (!second_list) + return first_list; + if (*second_list < 0) + return second_list; + const int *p; + for (p = first_list; *p >= 0; p++) + ; + int len = p - first_list; + for (p = second_list; *p >= 0; p++) + ; + if (p - second_list < len) + len = p - second_list; + int *matches = new int[len + 1]; + merge(matches, first_list, second_list); + while (ptr < end) { + const int *list = search1(&ptr, end); + if (list != 0) { + if (*list < 0) { + a_delete matches; + return list; + } + merge(matches, matches, list); + if (*matches < 0) { + a_delete matches; + return &minus_one; + } + } + } + *temp_listp = matches; + return matches; +} + +void index_search_item::read_common_words_file() +{ + if (header.common <= 0) + return; + const char *common_words_file = munge_filename(strchr(pool, '\0') + 1); + errno = 0; + FILE *fp = fopen(common_words_file, "r"); + if (!fp) { + error("can't open `%1': %2", common_words_file, strerror(errno)); + return; + } + common_words_table_size = 2*header.common + 1; + while (!is_prime(common_words_table_size)) + common_words_table_size++; + common_words_table = new char *[common_words_table_size]; + for (int i = 0; i < common_words_table_size; i++) + common_words_table[i] = 0; + int count = 0; + int key_len = 0; + for (;;) { + int c = getc(fp); + while (c != EOF && !csalnum(c)) + c = getc(fp); + if (c == EOF) + break; + do { + if (key_len < header.truncate) + key_buffer[key_len++] = cmlower(c); + c = getc(fp); + } while (c != EOF && csalnum(c)); + if (key_len >= header.shortest) { + int h = hash(key_buffer, key_len) % common_words_table_size; + while (common_words_table[h]) { + if (h == 0) + h = common_words_table_size; + --h; + } + common_words_table[h] = new char[key_len + 1]; + memcpy(common_words_table[h], key_buffer, key_len); + common_words_table[h][key_len] = '\0'; + } + if (++count >= header.common) + break; + key_len = 0; + if (c == EOF) + break; + } + fclose(fp); +} + +void index_search_item::add_out_of_date_file(int fd, const char *filename, + int fid) +{ + search_item **pp; + for (pp = &out_of_date_files; *pp; pp = &(*pp)->next) + if ((*pp)->is_named(filename)) + return; + *pp = make_linear_search_item(fd, filename, fid); + warning("`%1' modified since `%2' created", filename, name); +} + +void index_search_item::check_files() +{ + const char *pool_end = pool + header.strings_size; + for (const char *ptr = strchr(ignore_fields, '\0') + 1; + ptr < pool_end; + ptr = strchr(ptr, '\0') + 1) { + const char *path = munge_filename(ptr); + struct stat sb; + if (stat(path, &sb) < 0) + error("can't stat `%1': %2", path, strerror(errno)); + else if (sb.st_mtime > mtime) { + int fd = open(path, O_RDONLY | O_BINARY); + if (fd < 0) + error("can't open `%1': %2", path, strerror(errno)); + else + add_out_of_date_file(fd, path, filename_id + (ptr - pool)); + } + } +} diff --git a/contrib/groff/src/libs/libbib/linear.cc b/contrib/groff/src/libs/libbib/linear.cc new file mode 100644 index 0000000..a8c2a55 --- /dev/null +++ b/contrib/groff/src/libs/libbib/linear.cc @@ -0,0 +1,503 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "cmap.h" +#include "nonposix.h" + +#include "refid.h" +#include "search.h" + +class file_buffer { + char *buffer; + char *bufend; +public: + file_buffer(); + ~file_buffer(); + int load(int fd, const char *filename); + const char *get_start() const; + const char *get_end() const; +}; + +typedef unsigned char uchar; + +static uchar map[256]; +static uchar inv_map[256][3]; + +struct map_init { + map_init(); +}; + +static map_init the_map_init; + +map_init::map_init() +{ + int i; + for (i = 0; i < 256; i++) + map[i] = csalnum(i) ? cmlower(i) : '\0'; + for (i = 0; i < 256; i++) { + if (cslower(i)) { + inv_map[i][0] = i; + inv_map[i][1] = cmupper(i); + inv_map[i][2] = '\0'; + } + else if (csdigit(i)) { + inv_map[i][0] = i; + inv_map[i][1] = 0; + } + else + inv_map[i][0] = '\0'; + } +} + + +class bmpattern { + char *pat; + int len; + int delta[256]; +public: + bmpattern(const char *pattern, int pattern_length); + ~bmpattern(); + const char *search(const char *p, const char *end) const; + int length() const; +}; + +bmpattern::bmpattern(const char *pattern, int pattern_length) +: len(pattern_length) +{ + pat = new char[len]; + int i; + for (i = 0; i < len; i++) + pat[i] = map[uchar(pattern[i])]; + for (i = 0; i < 256; i++) + delta[i] = len; + for (i = 0; i < len; i++) + for (const unsigned char *inv = inv_map[uchar(pat[i])]; *inv; inv++) + delta[*inv] = len - i - 1; +} + +const char *bmpattern::search(const char *buf, const char *end) const +{ + int buflen = end - buf; + if (len > buflen) + return 0; + const char *strend; + if (buflen > len*4) + strend = end - len*4; + else + strend = buf; + const char *k = buf + len - 1; + const int *del = delta; + const char *pattern = pat; + for (;;) { + while (k < strend) { + int t = del[uchar(*k)]; + if (!t) + break; + k += t; + k += del[uchar(*k)]; + k += del[uchar(*k)]; + } + while (k < end && del[uchar(*k)] != 0) + k++; + if (k == end) + break; + int j = len - 1; + const char *s = k; + for (;;) { + if (j == 0) + return s; + if (map[uchar(*--s)] != uchar(pattern[--j])) + break; + } + k++; + } + return 0; +} + +bmpattern::~bmpattern() +{ + a_delete pat; +} + +inline int bmpattern::length() const +{ + return len; +} + + +static const char *find_end(const char *bufend, const char *p); + +const char *linear_searcher::search_and_check(const bmpattern *key, + const char *buf, const char *bufend, const char **start) const +{ + assert(buf[-1] == '\n'); + assert(bufend[-1] == '\n'); + const char *ptr = buf; + for (;;) { + const char *found = key->search(ptr, bufend); + if (!found) + break; + if (check_match(buf, bufend, found, key->length(), &ptr, start)) + return found; + } + return 0; +} + +static const char *skip_field(const char *end, const char *p) +{ + for (;;) + if (*p++ == '\n') { + if (p == end || *p == '%') + break; + const char *q; + for (q = p; *q == ' ' || *q == '\t'; q++) + ; + if (*q == '\n') + break; + p = q + 1; + } + return p; +} + +static const char *find_end(const char *bufend, const char *p) +{ + for (;;) + if (*p++ == '\n') { + if (p == bufend) + break; + const char *q; + for (q = p; *q == ' ' || *q == '\t'; q++) + ; + if (*q == '\n') + break; + p = q + 1; + } + return p; +} + + +int linear_searcher::check_match(const char *buf, const char *bufend, + const char *match, int matchlen, + const char **cont, const char **start) const +{ + *cont = match + 1; + // The user is required to supply only the first truncate_len characters + // of the key. If truncate_len <= 0, he must supply all the key. + if ((truncate_len <= 0 || matchlen < truncate_len) + && map[uchar(match[matchlen])] != '\0') + return 0; + + // The character before the match must not be an alphanumeric + // character (unless the alphanumeric character follows one or two + // percent characters at the beginning of the line), nor must it be + // a percent character at the beginning of a line, nor a percent + // character following a percent character at the beginning of a + // line. + + switch (match - buf) { + case 0: + break; + case 1: + if (match[-1] == '%' || map[uchar(match[-1])] != '\0') + return 0; + break; + case 2: + if (map[uchar(match[-1])] != '\0' && match[-2] != '%') + return 0; + if (match[-1] == '%' + && (match[-2] == '\n' || match[-2] == '%')) + return 0; + break; + default: + if (map[uchar(match[-1])] != '\0' + && !(match[-2] == '%' + && (match[-3] == '\n' + || (match[-3] == '%' && match[-4] == '\n')))) + return 0; + if (match[-1] == '%' + && (match[-2] == '\n' + || (match[-2] == '%' && match[-3] == '\n'))) + return 0; + } + + const char *p = match; + int had_percent = 0; + for (;;) { + if (*p == '\n') { + if (!had_percent && p[1] == '%') { + if (p[2] != '\0' && strchr(ignore_fields, p[2]) != 0) { + *cont = skip_field(bufend, match + matchlen); + return 0; + } + if (!start) + break; + had_percent = 1; + } + if (p <= buf) { + if (start) + *start = p + 1; + return 1; + } + const char *q; + for (q = p - 1; *q == ' ' || *q == '\t'; q--) + ; + if (*q == '\n') { + if (start) + *start = p + 1; + break; + } + p = q; + } + p--; + } + return 1; +} + +file_buffer::file_buffer() +: buffer(0), bufend(0) +{ +} + +file_buffer::~file_buffer() +{ + a_delete buffer; +} + +const char *file_buffer::get_start() const +{ + return buffer ? buffer + 4 : 0; +} + +const char *file_buffer::get_end() const +{ + return bufend; +} + +int file_buffer::load(int fd, const char *filename) +{ + struct stat sb; + if (fstat(fd, &sb) < 0) + error("can't fstat `%1': %2", filename, strerror(errno)); + else if (!S_ISREG(sb.st_mode)) + error("`%1' is not a regular file", filename); + else { + // We need one character extra at the beginning for an additional newline + // used as a sentinel. We get 4 instead so that the read buffer will be + // word-aligned. This seems to make the read slightly faster. We also + // need one character at the end also for an additional newline used as a + // sentinel. + int size = int(sb.st_size); + buffer = new char[size + 4 + 1]; + int nread = read(fd, buffer + 4, size); + if (nread < 0) + error("error reading `%1': %2", filename, strerror(errno)); + else if (nread != size) + error("size of `%1' decreased", filename); + else { + char c; + nread = read(fd, &c, 1); + if (nread != 0) + error("size of `%1' increased", filename); + else if (memchr(buffer + 4, '\0', size < 1024 ? size : 1024) != 0) + error("database `%1' is a binary file", filename); + else { + close(fd); + buffer[3] = '\n'; + int sidx = 4, didx = 4; + for ( ; sidx < size + 4; sidx++, didx++) + { + if (buffer[sidx] == '\r') + { + if (buffer[++sidx] != '\n') + buffer[didx++] = '\r'; + else + size--; + } + if (sidx != didx) + buffer[didx] = buffer[sidx]; + } + bufend = buffer + 4 + size; + if (bufend[-1] != '\n') + *bufend++ = '\n'; + return 1; + } + } + a_delete buffer; + buffer = 0; + } + close(fd); + return 0; +} + +linear_searcher::linear_searcher(const char *query, int query_len, + const char *ign, int trunc) +: ignore_fields(ign), truncate_len(trunc), keys(0), nkeys(0) +{ + const char *query_end = query + query_len; + int nk = 0; + const char *p; + for (p = query; p < query_end; p++) + if (map[uchar(*p)] != '\0' + && (p[1] == '\0' || map[uchar(p[1])] == '\0')) + nk++; + if (nk == 0) + return; + keys = new bmpattern*[nk]; + p = query; + for (;;) { + while (p < query_end && map[uchar(*p)] == '\0') + p++; + if (p == query_end) + break; + const char *start = p; + while (p < query_end && map[uchar(*p)] != '\0') + p++; + keys[nkeys++] = new bmpattern(start, p - start); + } + assert(nkeys <= nk); + if (nkeys == 0) { + a_delete keys; + keys = 0; + } +} + +linear_searcher::~linear_searcher() +{ + for (int i = 0; i < nkeys; i++) + delete keys[i]; + a_delete keys; +} + +int linear_searcher::search(const char *buffer, const char *bufend, + const char **startp, int *lengthp) const +{ + assert(bufend - buffer > 0); + assert(buffer[-1] == '\n'); + assert(bufend[-1] == '\n'); + if (nkeys == 0) + return 0; + for (;;) { + const char *refstart; + const char *found = search_and_check(keys[0], buffer, bufend, &refstart); + if (!found) + break; + const char *refend = find_end(bufend, found + keys[0]->length()); + int i; + for (i = 1; i < nkeys; i++) + if (!search_and_check(keys[i], refstart, refend)) + break; + if (i >= nkeys) { + *startp = refstart; + *lengthp = refend - refstart; + return 1; + } + buffer = refend; + } + return 0; +} + +class linear_search_item : public search_item { + file_buffer fbuf; +public: + linear_search_item(const char *filename, int fid); + ~linear_search_item(); + int load(int fd); + search_item_iterator *make_search_item_iterator(const char *); + friend class linear_search_item_iterator; +}; + +class linear_search_item_iterator : public search_item_iterator { + linear_search_item *lsi; + int pos; +public: + linear_search_item_iterator(linear_search_item *, const char *query); + ~linear_search_item_iterator(); + int next(const linear_searcher &, const char **ptr, int *lenp, + reference_id *ridp); +}; + +search_item *make_linear_search_item(int fd, const char *filename, int fid) +{ + linear_search_item *item = new linear_search_item(filename, fid); + if (!item->load(fd)) { + delete item; + return 0; + } + else + return item; +} + +linear_search_item::linear_search_item(const char *filename, int fid) +: search_item(filename, fid) +{ +} + +linear_search_item::~linear_search_item() +{ +} + +int linear_search_item::load(int fd) +{ + return fbuf.load(fd, name); +} + +search_item_iterator *linear_search_item::make_search_item_iterator( + const char *query) +{ + return new linear_search_item_iterator(this, query); +} + +linear_search_item_iterator::linear_search_item_iterator( + linear_search_item *p, const char *) +: lsi(p), pos(0) +{ +} + +linear_search_item_iterator::~linear_search_item_iterator() +{ +} + +int linear_search_item_iterator::next(const linear_searcher &searcher, + const char **startp, int *lengthp, + reference_id *ridp) +{ + const char *bufstart = lsi->fbuf.get_start(); + const char *bufend = lsi->fbuf.get_end(); + const char *ptr = bufstart + pos; + if (ptr < bufend && searcher.search(ptr, bufend, startp, lengthp)) { + pos = *startp + *lengthp - bufstart; + if (ridp) + *ridp = reference_id(lsi->filename_id, *startp - bufstart); + return 1; + } + else + return 0; +} diff --git a/contrib/groff/src/libs/libbib/map.c b/contrib/groff/src/libs/libbib/map.c new file mode 100644 index 0000000..ee5d008 --- /dev/null +++ b/contrib/groff/src/libs/libbib/map.c @@ -0,0 +1,71 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_MMAP + +#include <sys/types.h> +#include <sys/mman.h> + +/* The Net-2 man pages says that a MAP_FILE flag is required. */ +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +char *mapread(fd, nbytes) + int fd; + int nbytes; +{ + char *p = (char *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ, + MAP_FILE|MAP_PRIVATE, fd, (off_t)0); + if (p == (char *)-1) + return 0; + /* mmap() shouldn't return 0 since MAP_FIXED wasn't specified. */ + if (p == 0) + abort(); + return p; +} + +int unmap(p, len) + char *p; + int len; +{ + return munmap((caddr_t)p, len); +} + +#else /* not HAVE_MMAP */ + +#include <errno.h> + +char *mapread(fd, nbytes) + int fd; + int nbytes; +{ + errno = ENODEV; + return 0; +} + +int unmap(p, len) + char *p; + int len; +{ + errno = EINVAL; + return -1; +} + +#endif /* not HAVE_MMAP */ diff --git a/contrib/groff/src/libs/libbib/search.cc b/contrib/groff/src/libs/libbib/search.cc new file mode 100644 index 0000000..1e027c6 --- /dev/null +++ b/contrib/groff/src/libs/libbib/search.cc @@ -0,0 +1,132 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "nonposix.h" + +#include "refid.h" +#include "search.h" + +int linear_truncate_len = 6; +const char *linear_ignore_fields = "XYZ"; + +search_list::search_list() +: list(0), niterators(0), next_fid(1) +{ +} + +search_list::~search_list() +{ + assert(niterators == 0); + while (list) { + search_item *tem = list->next; + delete list; + list = tem; + } +} + +void search_list::add_file(const char *filename, int silent) +{ + search_item *p = make_index_search_item(filename, next_fid); + if (!p) { + int fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + if (!silent) + error("can't open `%1': %2", filename, strerror(errno)); + } + else + p = make_linear_search_item(fd, filename, next_fid); + } + if (p) { + search_item **pp; + for (pp = &list; *pp; pp = &(*pp)->next) + ; + *pp = p; + next_fid = p->next_filename_id(); + } +} + +int search_list::nfiles() const +{ + int n = 0; + for (search_item *ptr = list; ptr; ptr = ptr->next) + n++; + return n; +} + +search_list_iterator::search_list_iterator(search_list *p, const char *q) +: list(p), ptr(p->list), iter(0), query(strsave(q)), + searcher(q, strlen(q), linear_ignore_fields, linear_truncate_len) +{ + list->niterators += 1; +} + +search_list_iterator::~search_list_iterator() +{ + list->niterators -= 1; + a_delete query; + delete iter; +} + +int search_list_iterator::next(const char **pp, int *lenp, reference_id *ridp) +{ + while (ptr) { + if (iter == 0) + iter = ptr->make_search_item_iterator(query); + if (iter->next(searcher, pp, lenp, ridp)) + return 1; + delete iter; + iter = 0; + ptr = ptr->next; + } + return 0; +} + +search_item::search_item(const char *nm, int fid) +: name(strsave(nm)), filename_id(fid), next(0) +{ +} + +search_item::~search_item() +{ + a_delete name; +} + +int search_item::is_named(const char *nm) const +{ + return strcmp(name, nm) == 0; +} + +int search_item::next_filename_id() const +{ + return filename_id + 1; +} + +search_item_iterator::~search_item_iterator() +{ +} diff --git a/contrib/groff/src/libs/libdriver/Makefile.sub b/contrib/groff/src/libs/libdriver/Makefile.sub new file mode 100644 index 0000000..d50f060 --- /dev/null +++ b/contrib/groff/src/libs/libdriver/Makefile.sub @@ -0,0 +1,7 @@ +LIB=driver +OBJS=\ + input.o \ + printer.o +CCSRCS=\ + $(srcdir)/input.cc \ + $(srcdir)/printer.cc diff --git a/contrib/groff/src/libs/libdriver/input.cc b/contrib/groff/src/libs/libdriver/input.cc new file mode 100644 index 0000000..e19841c --- /dev/null +++ b/contrib/groff/src/libs/libdriver/input.cc @@ -0,0 +1,504 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2001 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "driver.h" +#include "device.h" +#include "cset.h" + +const char *current_filename=0; +int current_lineno; +const char *device = 0; +FILE *current_file; + +int get_integer(); // don't read the newline +int possibly_get_integer(int *); +char *get_string(int is_long = 0); +void skip_line(); + +struct environment_list { + environment env; + environment_list *next; + + environment_list(const environment &, environment_list *); +}; + +environment_list::environment_list(const environment &e, environment_list *p) +: env(e), next(p) +{ +} + +inline int get_char() +{ + return getc(current_file); +} + +/* + * remember_filename - is needed as get_string might overwrite the + * filename eventually. + */ + +void remember_filename(const char *filename) +{ + if (current_filename != 0) { + free((char *)current_filename); + } + if (strcmp(filename, "-") == 0) { + filename = "<standard input>"; + } + current_filename = (const char *)malloc(strlen(filename) + 1); + if (current_filename == 0) { + fatal("can't malloc space for filename"); + } + strcpy((char *)current_filename, (char *)filename); +} + +void do_file(const char *filename) +{ + int npages = 0; + if (filename[0] == '-' && filename[1] == '\0') { + remember_filename(filename); + current_file = stdin; + } + else { + errno = 0; + current_file = fopen(filename, "r"); + if (current_file == 0) { + error("can't open `%1'", filename); + return; + } + remember_filename(filename); + } + environment env; + env.vpos = -1; + env.hpos = -1; + env.fontno = -1; + env.height = 0; + env.slant = 0; + environment_list *env_list = 0; + current_lineno = 1; + int command; + char *s; + command = get_char(); + if (command == EOF) + return; + if (command != 'x') + fatal("the first command must be `x T'"); + s = get_string(); + if (s[0] != 'T') + fatal("the first command must be `x T'"); + char *dev = get_string(); + if (pr == 0) { + device = strsave(dev); + if (!font::load_desc()) + fatal("sorry, I can't continue"); + } + else { + if (device == 0 || strcmp(device, dev) != 0) + fatal("all files must use the same device"); + } + skip_line(); + env.size = 10*font::sizescale; + command = get_char(); + if (command != 'x') + fatal("the second command must be `x res'"); + s = get_string(); + if (s[0] != 'r') + fatal("the second command must be `x res'"); + int n = get_integer(); + if (n != font::res) + fatal("resolution does not match"); + n = get_integer(); + if (n != font::hor) + fatal("horizontal resolution does not match"); + n = get_integer(); + if (n != font::vert) + fatal("vertical resolution does not match"); + skip_line(); + command = get_char(); + if (command != 'x') + fatal("the third command must be `x init'"); + s = get_string(); + if (s[0] != 'i') + fatal("the third command must be `x init'"); + skip_line(); + if (pr == 0) + pr = make_printer(); + while ((command = get_char()) != EOF) { + switch (command) { + case 's': + env.size = get_integer(); + if (env.height == env.size) + env.height = 0; + break; + case 'f': + env.fontno = get_integer(); + break; + case 'F': + remember_filename(get_string()); + break; + case 'C': + { + if (npages == 0) + fatal("`C' command illegal before first `p' command"); + char *s = get_string(); + pr->set_special_char(s, &env); + } + break; + case 'N': + { + if (npages == 0) + fatal("`N' command illegal before first `p' command"); + pr->set_numbered_char(get_integer(), &env); + } + break; + case 'H': + env.hpos = get_integer(); + break; + case 'h': + env.hpos += get_integer(); + break; + case 'V': + env.vpos = get_integer(); + break; + case 'v': + env.vpos += get_integer(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + int c = get_char(); + if (!csdigit(c)) + fatal("digit expected"); + env.hpos += (command - '0')*10 + (c - '0'); + } + // fall through + case 'c': + { + if (npages == 0) + fatal("`c' command illegal before first `p' command"); + int c = get_char(); + if (c == EOF) + fatal("missing argument to `c' command"); + pr->set_ascii_char(c, &env); + } + break; + case 'n': + if (npages == 0) + fatal("`n' command illegal before first `p' command"); + pr->end_of_line(); + (void)get_integer(); + (void)get_integer(); + break; + case 'w': + case ' ': + break; + case '\n': + current_lineno++; + break; + case 'p': + if (npages) + pr->end_page(env.vpos); + npages++; + pr->begin_page(get_integer()); + env.vpos = 0; + break; + case '{': + env_list = new environment_list(env, env_list); + break; + case '}': + if (!env_list) { + fatal("can't pop"); + } + else { + env = env_list->env; + environment_list *tem = env_list; + env_list = env_list->next; + delete tem; + } + break; + case 'u': + { + if (npages == 0) + fatal("`u' command illegal before first `p' command"); + int kern = get_integer(); + int c = get_char(); + while (c == ' ') + c = get_char(); + while (c != EOF) { + if (c == '\n') { + current_lineno++; + break; + } + int w; + pr->set_ascii_char(c, &env, &w); + env.hpos += w + kern; + c = get_char(); + if (c == ' ') + break; + } + } + break; + case 't': + { + if (npages == 0) + fatal("`t' command illegal before first `p' command"); + int c; + while ((c = get_char()) != EOF && c != ' ') { + if (c == '\n') { + current_lineno++; + break; + } + int w; + pr->set_ascii_char(c, &env, &w); + env.hpos += w; + } + } + break; + case '#': + skip_line(); + break; + case 'D': + { + if (npages == 0) + fatal("`D' command illegal before first `p' command"); + int c; + while ((c = get_char()) == ' ') + ; + int n; + int *p = 0; + int szp = 0; + int np; + for (np = 0; possibly_get_integer(&n); np++) { + if (np >= szp) { + if (szp == 0) { + szp = 16; + p = new int[szp]; + } + else { + int *oldp = p; + p = new int[szp*2]; + memcpy(p, oldp, szp*sizeof(int)); + szp *= 2; + a_delete oldp; + } + } + p[np] = n; + } + pr->draw(c, p, np, &env); + if (c == 'e') { + if (np > 0) + env.hpos += p[0]; + } + else if (c == 'f' || c == 't') + ; + else { + int i; + for (i = 0; i < np/2; i++) { + env.hpos += p[i*2]; + env.vpos += p[i*2 + 1]; + } + // there might be an odd number of characters + if (i*2 < np) + env.hpos += p[i*2]; + } + a_delete p; + skip_line(); + } + break; + case 'x': + { + char *s = get_string(); + int suppress_skip = 0; + switch (s[0]) { + case 'i': + error("duplicate `x init' command"); + break; + case 'T': + error("duplicate `x T' command"); + break; + case 'r': + error("duplicate `x res' command"); + break; + case 'p': + break; + case 's': + break; + case 't': + break; + case 'f': + { + int n = get_integer(); + char *name = get_string(); + pr->load_font(n, name); + } + break; + case 'H': + env.height = get_integer(); + if (env.height == env.size) + env.height = 0; + break; + case 'S': + env.slant = get_integer(); + break; + case 'X': + if (npages == 0) + fatal("`x X' command illegal before first `p' command"); + pr->special(get_string(1), &env); + suppress_skip = 1; + break; + case 'u': + // .cu + pr->special(get_string(), &env, 'u'); + break; + default: + error("unrecognised x command `%1'", s); + } + if (!suppress_skip) + skip_line(); + } + break; + default: + error("unrecognised command code %1", int(command)); + skip_line(); + break; + } + } + if (npages) + pr->end_page(env.vpos); +} + +int get_integer() +{ + int c = get_char(); + while (c == ' ') + c = get_char(); + int neg = 0; + if (c == '-') { + neg = 1; + c = get_char(); + } + if (!csdigit(c)) + fatal("integer expected"); + int total = 0; + do { + total = total*10; + if (neg) + total -= c - '0'; + else + total += c - '0'; + c = get_char(); + } while (csdigit(c)); + if (c != EOF) + ungetc(c, current_file); + return total; +} + +int possibly_get_integer(int *res) +{ + int c = get_char(); + while (c == ' ') + c = get_char(); + int neg = 0; + if (c == '-') { + neg = 1; + c = get_char(); + } + if (!csdigit(c)) { + if (c != EOF) + ungetc(c, current_file); + return 0; + } + int total = 0; + do { + total = total*10; + if (neg) + total -= c - '0'; + else + total += c - '0'; + c = get_char(); + } while (csdigit(c)); + if (c != EOF) + ungetc(c, current_file); + *res = total; + return 1; +} + + +char *get_string(int is_long) +{ + static char *buf; + static int buf_size; + int c = get_char(); + while (c == ' ') + c = get_char(); + for (int i = 0;; i++) { + if (i >= buf_size) { + if (buf_size == 0) { + buf_size = 16; + buf = new char[buf_size]; + } + else { + char *old_buf = buf; + int old_size = buf_size; + buf_size *= 2; + buf = new char[buf_size]; + memcpy(buf, old_buf, old_size); + a_delete old_buf; + } + } + if ((!is_long && (c == ' ' || c == '\n')) || c == EOF) { + buf[i] = '\0'; + break; + } + if (is_long && c == '\n') { + current_lineno++; + c = get_char(); + if (c == '+') + c = '\n'; + else { + buf[i] = '\0'; + break; + } + } + buf[i] = c; + c = get_char(); + } + if (c != EOF) + ungetc(c, current_file); + return buf; +} + +void skip_line() +{ + int c; + while ((c = get_char()) != EOF) + if (c == '\n') { + current_lineno++; + break; + } +} diff --git a/contrib/groff/src/libs/libdriver/printer.cc b/contrib/groff/src/libs/libdriver/printer.cc new file mode 100644 index 0000000..4d66f7b --- /dev/null +++ b/contrib/groff/src/libs/libdriver/printer.cc @@ -0,0 +1,271 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2001 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "driver.h" + +printer *pr = 0; + +font_pointer_list::font_pointer_list(font *f, font_pointer_list *fp) +: p(f), next(fp) +{ +} + +printer::printer() +: font_list(0), font_table(0), nfonts(0) +{ +} + +printer::~printer() +{ + a_delete font_table; + while (font_list) { + font_pointer_list *tem = font_list; + font_list = font_list->next; + delete tem->p; + delete tem; + } + if (ferror(stdout) || fflush(stdout) < 0) + fatal("output error"); +} + +void printer::load_font(int n, const char *nm) +{ + assert(n >= 0); + if (n >= nfonts) { + if (nfonts == 0) { + nfonts = 10; + if (nfonts <= n) + nfonts = n + 1; + font_table = new font *[nfonts]; + for (int i = 0; i < nfonts; i++) + font_table[i] = 0; + } + else { + font **old_font_table = font_table; + int old_nfonts = nfonts; + nfonts *= 2; + if (n >= nfonts) + nfonts = n + 1; + font_table = new font *[nfonts]; + int i; + for (i = 0; i < old_nfonts; i++) + font_table[i] = old_font_table[i]; + for (i = old_nfonts; i < nfonts; i++) + font_table[i] = 0; + a_delete old_font_table; + } + } + font *f = find_font(nm); + font_table[n] = f; +} + +font *printer::find_font(const char *nm) +{ + for (font_pointer_list *p = font_list; p; p = p->next) + if (strcmp(p->p->get_name(), nm) == 0) + return p->p; + font *f = make_font(nm); + if (!f) + fatal("sorry, I can't continue"); + font_list = new font_pointer_list(f, font_list); + return f; +} + +font *printer::make_font(const char *nm) +{ + return font::load_font(nm); +} + +void printer::end_of_line() +{ +} + +void printer::special(char *, const environment *, char) +{ +} + +void printer::draw(int, int *, int, const environment *) +{ +} + +void printer::set_ascii_char(unsigned char c, const environment *env, + int *widthp) +{ + char buf[2]; + int w; + font *f; + + buf[0] = c; + buf[1] = '\0'; + + int i = set_char_and_width(buf, env, &w, &f); + set_char(i, f, env, w, 0); + if (widthp) { + *widthp = w; + } +} + +void printer::set_special_char(const char *nm, const environment *env, + int *widthp) +{ + font *f; + int w; + int i = set_char_and_width(nm, env, &w, &f); + if (i != -1) { + set_char(i, f, env, w, nm); + if (widthp) { + *widthp = w; + } + } +} + +int printer::set_char_and_width(const char *nm, const environment *env, + int *widthp, font **f) +{ + int i = font::name_to_index(nm); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return(-1); + } + *f = font_table[fn]; + if (*f == 0) { + error("no font mounted at `%1'", fn); + return(-1); + } + if (!(*f)->contains(i)) { + if (nm[0] != '\0' && nm[1] == '\0') + error("font `%1' does not contain ascii character `%2'", + (*f)->get_name(), + nm[0]); + else + error("font `%1' does not contain special character `%2'", + (*f)->get_name(), + nm); + return(-1); + } + int w = (*f)->get_width(i, env->size); + if (widthp) + *widthp = w; + return( i ); +} + +void printer::set_numbered_char(int num, const environment *env, int *widthp) +{ + int i = font::number_to_index(num); + int fn = env->fontno; + if (fn < 0 || fn >= nfonts) { + error("bad font position `%1'", fn); + return; + } + font *f = font_table[fn]; + if (f == 0) { + error("no font mounted at `%1'", fn); + return; + } + if (!f->contains(i)) { + error("font `%1' does not contain numbered character %2", + f->get_name(), + num); + return; + } + int w = f->get_width(i, env->size); + if (widthp) + *widthp = w; + set_char(i, f, env, w, 0); +} + +font *printer::get_font_from_index(int fontno) +{ + if ((fontno >= 0) && (fontno < nfonts)) + return(font_table[fontno]); + else + return(0); +} + +// This utility function adjusts the specified center of the +// arc so that it is equidistant between the specified start +// and end points. (p[0], p[1]) is a vector from the current +// point to the center; (p[2], p[3]) is a vector from the +// center to the end point. If the center can be adjusted, +// a vector from the current point to the adjusted center is +// stored in c[0], c[1] and 1 is returned. Otherwise 0 is +// returned. + +#if 1 +int printer::adjust_arc_center(const int *p, double *c) +{ + // We move the center along a line parallel to the line between + // the specified start point and end point so that the center + // is equidistant between the start and end point. + // It can be proved (using Lagrange multipliers) that this will + // give the point nearest to the specified center that is equidistant + // between the start and end point. + + double x = p[0] + p[2]; // (x, y) is the end point + double y = p[1] + p[3]; + double n = x*x + y*y; + if (n != 0) { + c[0]= double(p[0]); + c[1] = double(p[1]); + double k = .5 - (c[0]*x + c[1]*y)/n; + c[0] += k*x; + c[1] += k*y; + return 1; + } + else + return 0; +} +#else +int printer::adjust_arc_center(const int *p, double *c) +{ + int x = p[0] + p[2]; // (x, y) is the end point + int y = p[1] + p[3]; + // Start at the current point; go in the direction of the specified + // center point until we reach a point that is equidistant between + // the specified starting point and the specified end point. Place + // the center of the arc there. + double n = p[0]*double(x) + p[1]*double(y); + if (n > 0) { + double k = (double(x)*x + double(y)*y)/(2.0*n); + // (cx, cy) is our chosen center + c[0] = k*p[0]; + c[1] = k*p[1]; + return 1; + } + else { + // We would never reach such a point. So instead start at the + // specified end point of the arc. Go towards the specified + // center point until we reach a point that is equidistant between + // the specified start point and specified end point. Place + // the center of the arc there. + n = p[2]*double(x) + p[3]*double(y); + if (n > 0) { + double k = 1 - (double(x)*x + double(y)*y)/(2.0*n); + // (c[0], c[1]) is our chosen center + c[0] = p[0] + k*p[2]; + c[1] = p[1] + k*p[3]; + return 1; + } + else + return 0; + } +} +#endif diff --git a/contrib/groff/src/libs/libgroff/Makefile.sub b/contrib/groff/src/libs/libgroff/Makefile.sub new file mode 100644 index 0000000..5ce0691 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/Makefile.sub @@ -0,0 +1,84 @@ +LIB=groff +OBJS=\ + assert.o \ + change_lf.o \ + cmap.o \ + cset.o \ + device.o \ + errarg.o \ + error.o \ + fatal.o \ + filename.o \ + font.o \ + fontfile.o \ + getopt.o \ + getopt1.o \ + htmlindicate.o \ + illegal.o \ + lf.o \ + lineno.o \ + macropath.o \ + nametoindex.o \ + new.o \ + prime.o \ + progname.o \ + ptable.o \ + searchpath.o \ + string.o \ + strsave.o \ + tmpfile.o \ + iftoa.o \ + itoa.o \ + matherr.o \ + version.o \ + $(LIBOBJS) +CCSRCS=\ + $(srcdir)/assert.cc \ + $(srcdir)/change_lf.cc \ + $(srcdir)/cmap.cc \ + $(srcdir)/cset.cc \ + $(srcdir)/device.cc \ + $(srcdir)/errarg.cc \ + $(srcdir)/error.cc \ + $(srcdir)/fatal.cc \ + $(srcdir)/filename.cc \ + $(srcdir)/font.cc \ + $(srcdir)/fontfile.cc \ + $(srcdir)/htmlindicate.cc \ + $(srcdir)/illegal.cc \ + $(srcdir)/lf.cc \ + $(srcdir)/lineno.cc \ + $(srcdir)/macropath.cc \ + $(srcdir)/nametoindex.cc \ + $(srcdir)/new.cc \ + $(srcdir)/prime.cc \ + $(srcdir)/progname.cc \ + $(srcdir)/ptable.cc \ + $(srcdir)/searchpath.cc \ + $(srcdir)/string.cc \ + $(srcdir)/strsave.cc \ + $(srcdir)/tmpfile.cc \ + version.cc +CSRCS=\ + $(srcdir)/fmod.c \ + $(srcdir)/getcwd.c \ + $(srcdir)/getopt.c \ + $(srcdir)/getopt1.c \ + $(srcdir)/iftoa.c \ + $(srcdir)/itoa.c \ + $(srcdir)/matherr.c \ + $(srcdir)/putenv.c \ + $(srcdir)/strerror.c \ + $(srcdir)/strtol.c +GENSRCS=\ + version.cc + +version=`cat $(top_srcdir)/VERSION` +revision=`cat $(top_srcdir)/REVISION` + +version.cc: $(top_srcdir)/VERSION $(top_srcdir)/REVISION + @echo Making version.cc + @echo const char \*version_string = \"$(version)\"\; >$@ + @echo const char \*revision_string = \"$(revision)\"\; >>$@ + @echo const char \*Version_string = \"$(version).$(revision)\"\; | \ + sed -e 's/\.0\"/\"/' >>$@ diff --git a/contrib/groff/src/libs/libgroff/assert.cc b/contrib/groff/src/libs/libgroff/assert.cc new file mode 100644 index 0000000..89742e3 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/assert.cc @@ -0,0 +1,34 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include "assert.h" + +extern const char *program_name; + +void assertion_failed(int lineno, const char *filename) +{ + if (program_name != 0) + fprintf(stderr, "%s: ", program_name); + fprintf(stderr, "Failed assertion at line %d, file `%s'.\n", + lineno, filename); + fflush(stderr); + abort(); +} diff --git a/contrib/groff/src/libs/libgroff/change_lf.cc b/contrib/groff/src/libs/libgroff/change_lf.cc new file mode 100644 index 0000000..2e44af1 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/change_lf.cc @@ -0,0 +1,37 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <string.h> + +extern char *strsave(const char *); + +extern const char *current_filename; +extern int current_lineno; + +void change_filename(const char *f) +{ + if (current_filename != 0 && strcmp(current_filename, f) == 0) + return; + current_filename = strsave(f); +} + +void change_lineno(int ln) +{ + current_lineno = ln; +} diff --git a/contrib/groff/src/libs/libgroff/device.cc b/contrib/groff/src/libs/libgroff/device.cc new file mode 100644 index 0000000..7efbfef --- /dev/null +++ b/contrib/groff/src/libs/libgroff/device.cc @@ -0,0 +1,36 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdlib.h> +#include "device.h" +#include "defs.h" + +const char *device = DEVICE; + +struct device_init { + device_init(); +} _device_init; + +device_init::device_init() +{ + char *tem = getenv("GROFF_TYPESETTER"); + if (tem) + device = tem; +} diff --git a/contrib/groff/src/libs/libgroff/errarg.cc b/contrib/groff/src/libs/libgroff/errarg.cc new file mode 100644 index 0000000..f8075ea --- /dev/null +++ b/contrib/groff/src/libs/libgroff/errarg.cc @@ -0,0 +1,118 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include "assert.h" +#include "errarg.h" + +errarg::errarg(const char *p) : type(STRING) +{ + s = p ? p : "(null)"; +} + +errarg::errarg() : type(EMPTY) +{ +} + +errarg::errarg(unsigned char cc) : type(CHAR) +{ + c = cc; +} + +errarg::errarg(int nn) : type(INTEGER) +{ + n = nn; +} + +errarg::errarg(char cc) : type(CHAR) +{ + c = cc; +} + +errarg::errarg(double dd) : type(DOUBLE) +{ + d = dd; +} + +int errarg::empty() const +{ + return type == EMPTY; +} + +extern "C" { + const char *i_to_a(int); +} + +void errarg::print() const +{ + switch (type) { + case INTEGER: + fputs(i_to_a(n), stderr); + break; + case CHAR: + putc(c, stderr); + break; + case STRING: + fputs(s, stderr); + break; + case DOUBLE: + fprintf(stderr, "%g", d); + break; + case EMPTY: + break; + } +} + +errarg empty_errarg; + +void errprint(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + assert(format != 0); + char c; + while ((c = *format++) != '\0') { + if (c == '%') { + c = *format++; + switch(c) { + case '%': + fputc('%', stderr); + break; + case '1': + assert(!arg1.empty()); + arg1.print(); + break; + case '2': + assert(!arg2.empty()); + arg2.print(); + break; + case '3': + assert(!arg3.empty()); + arg3.print(); + break; + default: + assert(0); + } + } + else + putc(c, stderr); + } +} diff --git a/contrib/groff/src/libs/libgroff/error.cc b/contrib/groff/src/libs/libgroff/error.cc new file mode 100644 index 0000000..53fd629 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/error.cc @@ -0,0 +1,137 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "errarg.h" +#include "error.h" + +extern void fatal_error_exit(); + +enum error_type { WARNING, ERROR, FATAL }; + +static void do_error_with_file_and_line(const char *filename, int lineno, + error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + int need_space = 0; + if (program_name) { + fprintf(stderr, "%s:", program_name); + need_space = 1; + } + if (lineno >= 0 && filename != 0) { + if (strcmp(filename, "-") == 0) + filename = "<standard input>"; + fprintf(stderr, "%s:%d:", filename, lineno); + need_space = 1; + } + switch (type) { + case FATAL: + fputs("fatal error:", stderr); + need_space = 1; + break; + case ERROR: + break; + case WARNING: + fputs("warning:", stderr); + need_space = 1; + break; + } + if (need_space) + fputc(' ', stderr); + errprint(format, arg1, arg2, arg3); + fputc('\n', stderr); + fflush(stderr); + if (type == FATAL) + fatal_error_exit(); +} + + +static void do_error(error_type type, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(current_filename, current_lineno, + type, format, arg1, arg2, arg3); +} + + +void error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(ERROR, format, arg1, arg2, arg3); +} + +void warning(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(WARNING, format, arg1, arg2, arg3); +} + +void fatal(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error(FATAL, format, arg1, arg2, arg3); +} + +void error_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, lineno, + ERROR, format, arg1, arg2, arg3); +} + +void warning_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, lineno, + WARNING, format, arg1, arg2, arg3); +} + +void fatal_with_file_and_line(const char *filename, + int lineno, + const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + do_error_with_file_and_line(filename, lineno, + FATAL, format, arg1, arg2, arg3); +} diff --git a/contrib/groff/src/libs/libgroff/fatal.cc b/contrib/groff/src/libs/libgroff/fatal.cc new file mode 100644 index 0000000..42560dc --- /dev/null +++ b/contrib/groff/src/libs/libgroff/fatal.cc @@ -0,0 +1,27 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdlib.h> + +#define FATAL_ERROR_EXIT_CODE 3 + +void fatal_error_exit() +{ + exit(FATAL_ERROR_EXIT_CODE); +} diff --git a/contrib/groff/src/libs/libgroff/filename.cc b/contrib/groff/src/libs/libgroff/filename.cc new file mode 100644 index 0000000..1cbaa93 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/filename.cc @@ -0,0 +1 @@ +const char *current_filename = 0; diff --git a/contrib/groff/src/libs/libgroff/fmod.c b/contrib/groff/src/libs/libgroff/fmod.c new file mode 100644 index 0000000..818f946 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/fmod.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <math.h> + +double fmod(x, y) + double x, y; +{ + double quot = x/y; + return x - (quot < 0.0 ? ceil(quot) : floor(quot)) * y; +} + diff --git a/contrib/groff/src/libs/libgroff/font.cc b/contrib/groff/src/libs/libgroff/font.cc new file mode 100644 index 0000000..6cdd647 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/font.cc @@ -0,0 +1,938 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <math.h> +#include <stdlib.h> +#include "errarg.h" +#include "error.h" +#include "cset.h" +#include "font.h" +#include "lib.h" + +const char *const WS = " \t\n\r"; + +struct font_char_metric { + char type; + int code; + int width; + int height; + int depth; + int pre_math_space; + int italic_correction; + int subscript_correction; + char *special_device_coding; +}; + +struct font_kern_list { + int i1; + int i2; + int amount; + font_kern_list *next; + + font_kern_list(int, int, int, font_kern_list * = 0); +}; + +struct font_widths_cache { + font_widths_cache *next; + int point_size; + int *width; + + font_widths_cache(int, int, font_widths_cache * = 0); + ~font_widths_cache(); +}; + +/* text_file */ + +struct text_file { + FILE *fp; + char *path; + int lineno; + int size; + int skip_comments; + char *buf; + text_file(FILE *fp, char *p); + ~text_file(); + int next(); + void error(const char *format, + const errarg &arg1 = empty_errarg, + const errarg &arg2 = empty_errarg, + const errarg &arg3 = empty_errarg); +}; + +text_file::text_file(FILE *p, char *s) +: fp(p), path(s), lineno(0), size(0), skip_comments(1), buf(0) +{ +} + +text_file::~text_file() +{ + a_delete buf; + a_delete path; + if (fp) + fclose(fp); +} + + +int text_file::next() +{ + if (fp == 0) + return 0; + if (buf == 0) { + buf = new char [128]; + size = 128; + } + for (;;) { + int i = 0; + for (;;) { + int c = getc(fp); + if (c == EOF) + break; + if (illegal_input_char(c)) + error("illegal input character code `%1'", int(c)); + else { + if (i + 1 >= size) { + char *old_buf = buf; + buf = new char[size*2]; + memcpy(buf, old_buf, size); + a_delete old_buf; + size *= 2; + } + buf[i++] = c; + if (c == '\n') + break; + } + } + if (i == 0) + break; + buf[i] = '\0'; + lineno++; + char *ptr = buf; + while (csspace(*ptr)) + ptr++; + if (*ptr != 0 && (!skip_comments || *ptr != '#')) + return 1; + } + return 0; +} + +void text_file::error(const char *format, + const errarg &arg1, + const errarg &arg2, + const errarg &arg3) +{ + error_with_file_and_line(path, lineno, format, arg1, arg2, arg3); +} + + +/* font functions */ + +font::font(const char *s) +: ligatures(0), kern_hash_table(0), space_width(0), ch_index(0), nindices(0), + ch(0), ch_used(0), ch_size(0), special(0), widths_cache(0) +{ + name = new char[strlen(s) + 1]; + strcpy(name, s); + internalname = 0; + slant = 0.0; + // load(); // for testing +} + +font::~font() +{ + a_delete ch; + a_delete ch_index; + if (kern_hash_table) { + for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) { + font_kern_list *kerns = kern_hash_table[i]; + while (kerns) { + font_kern_list *tem = kerns; + kerns = kerns->next; + delete tem; + } + } + a_delete kern_hash_table; + } + a_delete name; + a_delete internalname; + while (widths_cache) { + font_widths_cache *tem = widths_cache; + widths_cache = widths_cache->next; + delete tem; + } +} + +static int scale_round(int n, int x, int y) +{ + assert(x >= 0 && y > 0); + int y2 = y/2; + if (x == 0) + return 0; + if (n >= 0) { + if (n <= (INT_MAX - y2)/x) + return (n*x + y2)/y; + return int(n*double(x)/double(y) + .5); + } + else { + if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x) + return (n*x - y2)/y; + return int(n*double(x)/double(y) - .5); + } +} + +inline int font::scale(int w, int sz) +{ + return sz == unitwidth ? w : scale_round(w, sz, unitwidth); +} + +int font::get_skew(int c, int point_size, int sl) +{ + int h = get_height(c, point_size); + return int(h*tan((slant+sl)*PI/180.0) + .5); +} + +int font::contains(int c) +{ + return c >= 0 && c < nindices && ch_index[c] >= 0; +} + +int font::is_special() +{ + return special; +} + +font_widths_cache::font_widths_cache(int ps, int ch_size, + font_widths_cache *p) +: next(p), point_size(ps) +{ + width = new int[ch_size]; + for (int i = 0; i < ch_size; i++) + width[i] = -1; +} + +font_widths_cache::~font_widths_cache() +{ + a_delete width; +} + +int font::get_width(int c, int point_size) +{ + assert(c >= 0 && c < nindices); + int i = ch_index[c]; + assert(i >= 0); + + if (point_size == unitwidth) + return ch[i].width; + + if (!widths_cache) + widths_cache = new font_widths_cache(point_size, ch_size); + else if (widths_cache->point_size != point_size) { + font_widths_cache **p; + for (p = &widths_cache; *p; p = &(*p)->next) + if ((*p)->point_size == point_size) + break; + if (*p) { + font_widths_cache *tem = *p; + *p = (*p)->next; + tem->next = widths_cache; + widths_cache = tem; + } + else + widths_cache = new font_widths_cache(point_size, ch_size, widths_cache); + } + int &w = widths_cache->width[i]; + if (w < 0) + w = scale(ch[i].width, point_size); + return w; +} + +int font::get_height(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].height, point_size); +} + +int font::get_depth(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].depth, point_size); +} + +int font::get_italic_correction(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].italic_correction, point_size); +} + +int font::get_left_italic_correction(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].pre_math_space, point_size); +} + +int font::get_subscript_correction(int c, int point_size) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return scale(ch[ch_index[c]].subscript_correction, point_size); +} + +int font::get_space_width(int point_size) +{ + return scale(space_width, point_size); +} + +font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p) + : i1(c1), i2(c2), amount(n), next(p) +{ +} + +inline int font::hash_kern(int i1, int i2) +{ + int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE; + return n < 0 ? -n : n; +} + +void font::add_kern(int i1, int i2, int amount) +{ + if (!kern_hash_table) { + kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE]; + for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) + kern_hash_table[i] = 0; + } + font_kern_list **p = kern_hash_table + hash_kern(i1, i2); + *p = new font_kern_list(i1, i2, amount, *p); +} + +int font::get_kern(int i1, int i2, int point_size) +{ + if (kern_hash_table) { + for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next) + if (i1 == p->i1 && i2 == p->i2) + return scale(p->amount, point_size); + } + return 0; +} + +int font::has_ligature(int mask) +{ + return mask & ligatures; +} + +int font::get_character_type(int c) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return ch[ch_index[c]].type; +} + +int font::get_code(int c) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return ch[ch_index[c]].code; +} + +const char *font::get_name() +{ + return name; +} + +const char *font::get_internal_name() +{ + return internalname; +} + +const char *font::get_special_device_encoding(int c) +{ + assert(c >= 0 && c < nindices && ch_index[c] >= 0); + return( ch[ch_index[c]].special_device_coding ); +} + +void font::alloc_ch_index(int index) +{ + if (nindices == 0) { + nindices = 128; + if (index >= nindices) + nindices = index + 10; + ch_index = new short[nindices]; + for (int i = 0; i < nindices; i++) + ch_index[i] = -1; + } + else { + int old_nindices = nindices; + nindices *= 2; + if (index >= nindices) + nindices = index + 10; + short *old_ch_index = ch_index; + ch_index = new short[nindices]; + memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices); + for (int i = old_nindices; i < nindices; i++) + ch_index[i] = -1; + a_delete old_ch_index; + } +} + +void font::extend_ch() +{ + if (ch == 0) + ch = new font_char_metric[ch_size = 16]; + else { + int old_ch_size = ch_size; + ch_size *= 2; + font_char_metric *old_ch = ch; + ch = new font_char_metric[ch_size]; + memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric)); + a_delete old_ch; + } +} + +void font::compact() +{ + int i; + for (i = nindices - 1; i >= 0; i--) + if (ch_index[i] >= 0) + break; + i++; + if (i < nindices) { + short *old_ch_index = ch_index; + ch_index = new short[i]; + memcpy(ch_index, old_ch_index, i*sizeof(short)); + a_delete old_ch_index; + nindices = i; + } + if (ch_used < ch_size) { + font_char_metric *old_ch = ch; + ch = new font_char_metric[ch_used]; + memcpy(ch, old_ch, ch_used*sizeof(font_char_metric)); + a_delete old_ch; + ch_size = ch_used; + } +} + +void font::add_entry(int index, const font_char_metric &metric) +{ + assert(index >= 0); + if (index >= nindices) + alloc_ch_index(index); + assert(index < nindices); + if (ch_used + 1 >= ch_size) + extend_ch(); + assert(ch_used + 1 < ch_size); + ch_index[index] = ch_used; + ch[ch_used++] = metric; +} + +void font::copy_entry(int new_index, int old_index) +{ + assert(new_index >= 0 && old_index >= 0 && old_index < nindices); + if (new_index >= nindices) + alloc_ch_index(new_index); + ch_index[new_index] = ch_index[old_index]; +} + +font *font::load_font(const char *s, int *not_found) +{ + font *f = new font(s); + if (!f->load(not_found)) { + delete f; + return 0; + } + return f; +} + +static char *trim_arg(char *p) +{ + if (!p) + return 0; + while (csspace(*p)) + p++; + char *q = strchr(p, '\0'); + while (q > p && csspace(q[-1])) + q--; + *q = '\0'; + return p; +} + +// If the font can't be found, then if not_found is non-NULL, it will be set +// to 1 otherwise a message will be printed. + +int font::load(int *not_found) +{ + char *path; + FILE *fp; + if ((fp = open_file(name, &path)) == NULL) { + if (not_found) + *not_found = 1; + else + error("can't find font file `%1'", name); + return 0; + } + text_file t(fp, path); + t.skip_comments = 1; + char *p; + for (;;) { + if (!t.next()) { + t.error("missing charset command"); + return 0; + } + p = strtok(t.buf, WS); + if (strcmp(p, "name") == 0) { + } + else if (strcmp(p, "spacewidth") == 0) { + p = strtok(0, WS); + int n; + if (p == 0 || sscanf(p, "%d", &n) != 1 || n <= 0) { + t.error("bad argument for spacewidth command"); + return 0; + } + space_width = n; + } + else if (strcmp(p, "slant") == 0) { + p = strtok(0, WS); + double n; + if (p == 0 || sscanf(p, "%lf", &n) != 1 || n >= 90.0 || n <= -90.0) { + t.error("bad argument for slant command", p); + return 0; + } + slant = n; + } + else if (strcmp(p, "ligatures") == 0) { + for (;;) { + p = strtok(0, WS); + if (p == 0 || strcmp(p, "0") == 0) + break; + if (strcmp(p, "ff") == 0) + ligatures |= LIG_ff; + else if (strcmp(p, "fi") == 0) + ligatures |= LIG_fi; + else if (strcmp(p, "fl") == 0) + ligatures |= LIG_fl; + else if (strcmp(p, "ffi") == 0) + ligatures |= LIG_ffi; + else if (strcmp(p, "ffl") == 0) + ligatures |= LIG_ffl; + else { + t.error("unrecognised ligature `%1'", p); + return 0; + } + } + } + else if (strcmp(p, "internalname") == 0) { + p = strtok(0, WS); + if (!p) { + t.error("`internalname command requires argument"); + return 0; + } + internalname = new char[strlen(p) + 1]; + strcpy(internalname, p); + } + else if (strcmp(p, "special") == 0) { + special = 1; + } + else if (strcmp(p, "kernpairs") != 0 && strcmp(p, "charset") != 0) { + char *command = p; + p = strtok(0, "\n"); + handle_unknown_font_command(command, trim_arg(p), t.path, t.lineno); + } + else + break; + } + char *command = p; + int had_charset = 0; + t.skip_comments = 0; + while (command) { + if (strcmp(command, "kernpairs") == 0) { + for (;;) { + if (!t.next()) { + command = 0; + break; + } + char *c1 = strtok(t.buf, WS); + if (c1 == 0) + continue; + char *c2 = strtok(0, WS); + if (c2 == 0) { + command = c1; + break; + } + p = strtok(0, WS); + if (p == 0) { + t.error("missing kern amount"); + return 0; + } + int n; + if (sscanf(p, "%d", &n) != 1) { + t.error("bad kern amount `%1'", p); + return 0; + } + int i1 = name_to_index(c1); + if (i1 < 0) { + t.error("illegal character `%1'", c1); + return 0; + } + int i2 = name_to_index(c2); + if (i2 < 0) { + t.error("illegal character `%1'", c2); + return 0; + } + add_kern(i1, i2, n); + } + } + else if (strcmp(command, "charset") == 0) { + had_charset = 1; + int last_index = -1; + for (;;) { + if (!t.next()) { + command = 0; + break; + } + char *nm = strtok(t.buf, WS); + if (nm == 0) + continue; // I dont think this should happen + p = strtok(0, WS); + if (p == 0) { + command = nm; + break; + } + if (p[0] == '"') { + if (last_index == -1) { + t.error("first charset entry is duplicate"); + return 0; + } + if (strcmp(nm, "---") == 0) { + t.error("unnamed character cannot be duplicate"); + return 0; + } + int index = name_to_index(nm); + if (index < 0) { + t.error("illegal character `%1'", nm); + return 0; + } + copy_entry(index, last_index); + } + else { + font_char_metric metric; + metric.height = 0; + metric.depth = 0; + metric.pre_math_space = 0; + metric.italic_correction = 0; + metric.subscript_correction = 0; + int nparms = sscanf(p, "%d,%d,%d,%d,%d,%d", + &metric.width, &metric.height, &metric.depth, + &metric.italic_correction, + &metric.pre_math_space, + &metric.subscript_correction); + if (nparms < 1) { + t.error("bad width for `%1'", nm); + return 0; + } + p = strtok(0, WS); + if (p == 0) { + t.error("missing character type for `%1'", nm); + return 0; + } + int type; + if (sscanf(p, "%d", &type) != 1) { + t.error("bad character type for `%1'", nm); + return 0; + } + if (type < 0 || type > 255) { + t.error("character code `%1' out of range", type); + return 0; + } + metric.type = type; + p = strtok(0, WS); + if (p == 0) { + t.error("missing code for `%1'", nm); + return 0; + } + char *ptr; + metric.code = (int)strtol(p, &ptr, 0); + if (metric.code == 0 && ptr == p) { + t.error("bad code `%1' for character `%2'", p, nm); + return 0; + } + + p = strtok(0, WS); + if ((p == NULL) || (strcmp(p, "--") == 0)) { + metric.special_device_coding = NULL; + } else { + char *name=(char *)malloc(strlen(p)+1); + + if (name == NULL) { + fatal("malloc failed while reading character encoding"); + } + strcpy(name, p); + metric.special_device_coding = name; + } + + if (strcmp(nm, "---") == 0) { + last_index = number_to_index(metric.code); + add_entry(last_index, metric); + } + else { + last_index = name_to_index(nm); + if (last_index < 0) { + t.error("illegal character `%1'", nm); + return 0; + } + add_entry(last_index, metric); + copy_entry(number_to_index(metric.code), last_index); + } + } + } + if (last_index == -1) { + t.error("I didn't seem to find any characters"); + return 0; + } + } + else { + t.error("unrecognised command `%1' after `kernpairs' or `charset' command", command); + return 0; + } + } + if (!had_charset) { + t.error("missing charset command"); + return 0; + } + if (space_width == 0) + space_width = scale_round(unitwidth, res, 72*3*sizescale); + compact(); + return 1; +} + +static struct { + const char *command; + int *ptr; +} table[] = { + { "res", &font::res }, + { "hor", &font::hor }, + { "vert", &font::vert }, + { "unitwidth", &font::unitwidth }, + { "paperwidth", &font::paperwidth }, + { "paperlength", &font::paperlength }, + { "spare1", &font::biggestfont }, + { "biggestfont", &font::biggestfont }, + { "spare2", &font::spare2 }, + { "sizescale", &font::sizescale } + }; + + +int font::load_desc() +{ + int nfonts = 0; + FILE *fp; + char *path; + if ((fp = open_file("DESC", &path)) == 0) { + error("can't find `DESC' file"); + return 0; + } + text_file t(fp, path); + t.skip_comments = 1; + res = 0; + while (t.next()) { + char *p = strtok(t.buf, WS); + int found = 0; + int idx; + for (idx = 0; !found && idx < sizeof(table)/sizeof(table[0]); idx++) + if (strcmp(table[idx].command, p) == 0) + found = 1; + if (found) { + char *q = strtok(0, WS); + if (!q) { + t.error("missing value for command `%1'", p); + return 0; + } + //int *ptr = &(this->*(table[idx-1].ptr)); + int *ptr = table[idx-1].ptr; + if (sscanf(q, "%d", ptr) != 1) { + t.error("bad number `%1'", q); + return 0; + } + } + else if (strcmp("tcommand", p) == 0) { + tcommand = 1; + } + else if (strcmp("pass_filenames", p) == 0) { + pass_filenames = 1; + } + else if (strcmp("use_charnames_in_special", p) == 0) { + use_charnames_in_special = 1; + } + else if (strcmp("family", p) == 0) { + p = strtok(0, WS); + if (!p) { + t.error("family command requires an argument"); + return 0; + } + char *tem = new char[strlen(p)+1]; + strcpy(tem, p); + family = tem; + } + else if (strcmp("fonts", p) == 0) { + p = strtok(0, WS); + if (!p || sscanf(p, "%d", &nfonts) != 1 || nfonts <= 0) { + t.error("bad number of fonts `%1'", p); + return 0; + } + font_name_table = (const char **)new char *[nfonts+1]; + for (int i = 0; i < nfonts; i++) { + p = strtok(0, WS); + while (p == 0) { + if (!t.next()) { + t.error("end of file while reading list of fonts"); + return 0; + } + p = strtok(t.buf, WS); + } + char *temp = new char[strlen(p)+1]; + strcpy(temp, p); + font_name_table[i] = temp; + } + p = strtok(0, WS); + if (p != 0) { + t.error("font count does not match number of fonts"); + return 0; + } + font_name_table[nfonts] = 0; + } + else if (strcmp("sizes", p) == 0) { + int n = 16; + sizes = new int[n]; + int i = 0; + for (;;) { + p = strtok(0, WS); + while (p == 0) { + if (!t.next()) { + t.error("list of sizes must be terminated by `0'"); + return 0; + } + p = strtok(t.buf, WS); + } + int lower, upper; + switch (sscanf(p, "%d-%d", &lower, &upper)) { + case 1: + upper = lower; + // fall through + case 2: + if (lower <= upper && lower >= 0) + break; + // fall through + default: + t.error("bad size range `%1'", p); + return 0; + } + if (i + 2 > n) { + int *old_sizes = sizes; + sizes = new int[n*2]; + memcpy(sizes, old_sizes, n*sizeof(int)); + n *= 2; + a_delete old_sizes; + } + sizes[i++] = lower; + if (lower == 0) + break; + sizes[i++] = upper; + } + if (i == 1) { + t.error("must have some sizes"); + return 0; + } + } + else if (strcmp("styles", p) == 0) { + int style_table_size = 5; + style_table = (const char **)new char *[style_table_size]; + int j; + for (j = 0; j < style_table_size; j++) + style_table[j] = 0; + int i = 0; + for (;;) { + p = strtok(0, WS); + if (p == 0) + break; + // leave room for terminating 0 + if (i + 1 >= style_table_size) { + const char **old_style_table = style_table; + style_table_size *= 2; + style_table = (const char **)new char*[style_table_size]; + for (j = 0; j < i; j++) + style_table[j] = old_style_table[j]; + for (; j < style_table_size; j++) + style_table[j] = 0; + a_delete old_style_table; + } + char *tem = new char[strlen(p) + 1]; + strcpy(tem, p); + style_table[i++] = tem; + } + } + else if (strcmp("charset", p) == 0) + break; + else if (unknown_desc_command_handler) { + char *command = p; + p = strtok(0, "\n"); + (*unknown_desc_command_handler)(command, trim_arg(p), t.path, t.lineno); + } + } + if (res == 0) { + t.error("missing `res' command"); + return 0; + } + if (unitwidth == 0) { + t.error("missing `unitwidth' command"); + return 0; + } + if (font_name_table == 0) { + t.error("missing `fonts' command"); + return 0; + } + if (sizes == 0) { + t.error("missing `sizes' command"); + return 0; + } + if (sizescale < 1) { + t.error("bad `sizescale' value"); + return 0; + } + if (hor < 1) { + t.error("bad `hor' value"); + return 0; + } + if (vert < 1) { + t.error("bad `vert' value"); + return 0; + } + return 1; +} + +void font::handle_unknown_font_command(const char *, const char *, + const char *, int) +{ +} + +FONT_COMMAND_HANDLER +font::set_unknown_desc_command_handler(FONT_COMMAND_HANDLER func) +{ + FONT_COMMAND_HANDLER prev = unknown_desc_command_handler; + unknown_desc_command_handler = func; + return prev; +} + diff --git a/contrib/groff/src/libs/libgroff/fontfile.cc b/contrib/groff/src/libs/libgroff/fontfile.cc new file mode 100644 index 0000000..cc1ad2c --- /dev/null +++ b/contrib/groff/src/libs/libgroff/fontfile.cc @@ -0,0 +1,66 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <stdlib.h> +#include <errno.h> +#include "font.h" +#include "lib.h" +#include "searchpath.h" +#include "device.h" +#include "defs.h" + +const char *const FONT_ENV_VAR = "GROFF_FONT_PATH"; + +static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0); + +int font::res = 0; +int font::hor = 1; +int font::vert = 1; +int font::unitwidth = 0; +int font::paperwidth = 0; +int font::paperlength = 0; +int font::biggestfont = 0; +int font::spare2 = 0; +int font::sizescale = 1; +int font::tcommand = 0; +int font::pass_filenames = 0; +int font::use_charnames_in_special = 0; +const char **font::font_name_table = 0; +int *font::sizes = 0; +const char *font::family = 0; +const char **font::style_table = 0; +FONT_COMMAND_HANDLER font::unknown_desc_command_handler = 0; + +void font::command_line_font_dir(const char *dir) +{ + font_path.command_line_dir(dir); +} + +FILE *font::open_file(const char *name, char **pathp) +{ + char *filename = new char[strlen(name) + strlen(device) + 5]; + sprintf(filename, "dev%s/%s", device, name); + FILE *fp = font_path.open_file(filename, pathp); + a_delete filename; + return fp; +} diff --git a/contrib/groff/src/libs/libgroff/getcwd.c b/contrib/groff/src/libs/libgroff/getcwd.c new file mode 100644 index 0000000..7a769ff --- /dev/null +++ b/contrib/groff/src/libs/libgroff/getcwd.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Partial emulation of getcwd in terms of getwd. */ + +#include <sys/param.h> +#include <string.h> +#include <errno.h> + +char *getwd(); + +char *getcwd(buf, size) + char *buf; + int size; /* POSIX says this should be size_t */ +{ + if (size <= 0) { + errno = EINVAL; + return 0; + } + else { + char mybuf[MAXPATHLEN]; + int saved_errno = errno; + + errno = 0; + if (!getwd(mybuf)) { + if (errno == 0) + ; /* what to do? */ + return 0; + } + errno = saved_errno; + if (strlen(mybuf) + 1 > size) { + errno = ERANGE; + return 0; + } + strcpy(buf, mybuf); + return buf; + } +} diff --git a/contrib/groff/src/libs/libgroff/getopt.c b/contrib/groff/src/libs/libgroff/getopt.c new file mode 100644 index 0000000..4744e43 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/getopt.c @@ -0,0 +1,1055 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to drepper@gnu.org + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 + Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include <gnu-versions.h> +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include <stdlib.h> +# include <unistd.h> +#endif /* GNU C library. */ + +#ifdef VMS +# include <unixlib.h> +# if HAVE_STRING_H - 0 +# include <string.h> +# endif +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +# ifdef HAVE_LIBINTL_H +# include <libintl.h> +# define _(msgid) gettext (msgid) +# else +# define _(msgid) (msgid) +# endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include <string.h> +# define my_index strchr +#else + +# if HAVE_STRING_H +# include <string.h> +# else +# include <strings.h> +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#ifndef getenv +extern char *getenv (); +#endif + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int print_errors = opterr; + if (optstring[0] == ':') + print_errors = 0; + + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (print_errors) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (print_errors) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (print_errors) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (print_errors) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (print_errors) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/contrib/groff/src/libs/libgroff/getopt1.c b/contrib/groff/src/libs/libgroff/getopt1.c new file mode 100644 index 0000000..3d264f2 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/getopt1.c @@ -0,0 +1,188 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. 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 "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include <gnu-versions.h> +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include <stdio.h> + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/contrib/groff/src/libs/libgroff/htmlindicate.cc b/contrib/groff/src/libs/libgroff/htmlindicate.cc new file mode 100644 index 0000000..2e6a5d7 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/htmlindicate.cc @@ -0,0 +1,97 @@ +/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Written by Gaius Mulley (gaius@glam.ac.uk) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "nonposix.h" +#include "stringclass.h" +#include "html-strings.h" + +/* + * This file contains a very simple set of routines shared by + * tbl, pic, eqn which help the html device driver to make + * sensible formatting choices. Currently it simply indicates + * to pre-html when an image is about to be created this is then + * passes to pre-html. + * Pre-html runs troff twice, once with -Thtml and once with -Tps. + * troff -Thtml device driver emits a <src='image'.png> tag + * and the postscript device driver works out the min/max limits + * of the graphic region. These region limits are read by pre-html + * and an image is generated via troff -Tps -> gs -> png + */ + +static int is_in_graphic_start = 0; +static int is_inline_image = 0; + +/* + * html_begin_suppress - emit a start of image tag which will be seen + * by pre-html. + */ +void html_begin_suppress(int is_inline) +{ + if (is_inline) + put_string(HTML_IMAGE_INLINE_BEGIN, stdout); + else { + put_string(HTML_IMAGE_CENTERED, stdout); + put_string("\n", stdout); + } +} + +/* + * html_end_suppress - emit an end of image tag which will be seen + * by pre-html. + */ +void html_end_suppress(int is_inline) +{ + if (is_inline) + put_string(HTML_IMAGE_INLINE_END, stdout); + else { + put_string(HTML_IMAGE_END, stdout); + put_string("\n", stdout); + } +} + +/* + * graphic_start - The boolean, is_inline, should be: + * + * FALSE if this is called via EQ, TS, PS, and + * TRUE if issued via delim $$ $ x over y $ etc. + */ +void graphic_start(int is_inline) +{ + if (!is_in_graphic_start) { + html_begin_suppress(is_inline); + is_inline_image = is_inline; + is_in_graphic_start = 1; + } +} + +/* + * graphic_end - tell troff that the image region is ending. + */ + +void graphic_end() +{ + if (is_in_graphic_start) { + html_end_suppress(is_inline_image); + is_in_graphic_start = 0; + } +} diff --git a/contrib/groff/src/libs/libgroff/iftoa.c b/contrib/groff/src/libs/libgroff/iftoa.c new file mode 100644 index 0000000..29a3d89 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/iftoa.c @@ -0,0 +1,65 @@ +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define INT_DIGITS 19 /* enough for 64-bit integer */ + +char *if_to_a(i, decimal_point) + int i, decimal_point; +{ + /* room for a -, INT_DIGITS digits, a decimal point, and a terminating '\0' */ + static char buf[INT_DIGITS + 3]; + char *p = buf + INT_DIGITS + 2; + int point = 0; + buf[INT_DIGITS + 2] = '\0'; + /* assert(decimal_point <= INT_DIGITS); */ + if (i >= 0) { + do { + *--p = '0' + (i % 10); + i /= 10; + if (++point == decimal_point) + *--p = '.'; + } while (i != 0 || point < decimal_point); + } + else { /* i < 0 */ + do { + *--p = '0' - (i % 10); + i /= 10; + if (++point == decimal_point) + *--p = '.'; + } while (i != 0 || point < decimal_point); + *--p = '-'; + } + if (decimal_point > 0) { + char *q; + /* there must be a dot, so this will terminate */ + for (q = buf + INT_DIGITS + 2; q[-1] == '0'; --q) + ; + if (q[-1] == '.') { + if (q - 1 == p) { + q[-1] = '0'; + q[0] = '\0'; + } + else + q[-1] = '\0'; + } + else + *q = '\0'; + } + return p; +} diff --git a/contrib/groff/src/libs/libgroff/illegal.cc b/contrib/groff/src/libs/libgroff/illegal.cc index c1bdbc5..bacd891 100644 --- a/contrib/groff/src/libs/libgroff/illegal.cc +++ b/contrib/groff/src/libs/libgroff/illegal.cc @@ -1,3 +1,22 @@ +/* Copyright (C) 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + #include "lib.h" // Table of illegal input characters. diff --git a/contrib/groff/src/libs/libgroff/itoa.c b/contrib/groff/src/libs/libgroff/itoa.c new file mode 100644 index 0000000..72826b7 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/itoa.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define INT_DIGITS 19 /* enough for 64 bit integer */ + +char *i_to_a(i) + int i; +{ + /* Room for INT_DIGITS digits, - and '\0' */ + static char buf[INT_DIGITS + 2]; + char *p = buf + INT_DIGITS + 1; /* points to terminating '\0' */ + if (i >= 0) { + do { + *--p = '0' + (i % 10); + i /= 10; + } while (i != 0); + return p; + } + else { /* i < 0 */ + do { + *--p = '0' - (i % 10); + i /= 10; + } while (i != 0); + *--p = '-'; + } + return p; +} diff --git a/contrib/groff/src/libs/libgroff/lf.cc b/contrib/groff/src/libs/libgroff/lf.cc new file mode 100644 index 0000000..34272c7 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/lf.cc @@ -0,0 +1,62 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <string.h> +#include <ctype.h> +#include "cset.h" +#include "stringclass.h" + +extern void change_filename(const char *); +extern void change_lineno(int); + +int interpret_lf_args(const char *p) +{ + while (*p == ' ') + p++; + if (!csdigit(*p)) + return 0; + int ln = 0; + do { + ln *= 10; + ln += *p++ - '0'; + } while (csdigit(*p)); + if (*p != ' ' && *p != '\n' && *p != '\0') + return 0; + while (*p == ' ') + p++; + if (*p == '\0' || *p == '\n') { + change_lineno(ln); + return 1; + } + const char *q; + for (q = p; + *q != '\0' && *q != ' ' && *q != '\n' && *q != '\\'; + q++) + ; + string tem(p, q - p); + while (*q == ' ') + q++; + if (*q != '\n' && *q != '\0') + return 0; + tem += '\0'; + change_filename(tem.contents()); + change_lineno(ln); + return 1; +} diff --git a/contrib/groff/src/libs/libgroff/lineno.cc b/contrib/groff/src/libs/libgroff/lineno.cc new file mode 100644 index 0000000..f7138db --- /dev/null +++ b/contrib/groff/src/libs/libgroff/lineno.cc @@ -0,0 +1 @@ +int current_lineno = 0; diff --git a/contrib/groff/src/libs/libgroff/macropath.cc b/contrib/groff/src/libs/libgroff/macropath.cc new file mode 100644 index 0000000..03c04cb --- /dev/null +++ b/contrib/groff/src/libs/libgroff/macropath.cc @@ -0,0 +1,30 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "lib.h" +#include "searchpath.h" +#include "macropath.h" +#include "defs.h" + +#define MACROPATH_ENVVAR "GROFF_TMAC_PATH" + +search_path macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 1); +search_path safer_macro_path(MACROPATH_ENVVAR, MACROPATH, 1, 0); +search_path config_macro_path(MACROPATH_ENVVAR, MACROPATH, 0, 0); diff --git a/contrib/groff/src/libs/libgroff/matherr.c b/contrib/groff/src/libs/libgroff/matherr.c new file mode 100644 index 0000000..b0097b8 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/matherr.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <math.h> +#include <errno.h> + +#ifdef HAVE_STRUCT_EXCEPTION +#ifdef TLOSS + +int matherr(exc) +struct exception *exc; +{ + switch (exc->type) { + case SING: + case DOMAIN: + errno = EDOM; + break; + case OVERFLOW: + case UNDERFLOW: + case TLOSS: + case PLOSS: + errno = ERANGE; + break; + } + return 1; +} + +#endif /* TLOSS */ +#endif /* HAVE_STRUCT_EXCEPTION */ diff --git a/contrib/groff/src/libs/libgroff/nametoindex.cc b/contrib/groff/src/libs/libgroff/nametoindex.cc new file mode 100644 index 0000000..578ff34 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/nametoindex.cc @@ -0,0 +1,118 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <stdlib.h> +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "font.h" +#include "ptable.h" + +declare_ptable(int) +implement_ptable(int) + +class character_indexer { +public: + character_indexer(); + ~character_indexer(); + int ascii_char_index(unsigned char); + int named_char_index(const char *); + int numbered_char_index(int); +private: + enum { NSMALL = 256 }; + int next_index; + int ascii_index[256]; + int small_number_index[NSMALL]; + PTABLE(int) table; + int lookup_char(const char *, int); +}; + +character_indexer::character_indexer() +: next_index(0) +{ + int i; + for (i = 0; i < 256; i++) + ascii_index[i] = -1; + for (i = 0; i < NSMALL; i++) + small_number_index[i] = -1; +} + +character_indexer::~character_indexer() +{ +} + +int character_indexer::ascii_char_index(unsigned char c) +{ + if (ascii_index[c] < 0) + ascii_index[c] = next_index++; + return ascii_index[c]; +} + +int character_indexer::numbered_char_index(int n) +{ + if (n >= 0 && n < NSMALL) { + if (small_number_index[n] < 0) + small_number_index[n] = next_index++; + return small_number_index[n]; + } + // Not the most efficient possible implementation. + char buf[INT_DIGITS + 3]; + buf[0] = ' '; + strcpy(buf + 1, i_to_a(n)); + return named_char_index(buf); +} + +int character_indexer::named_char_index(const char *s) +{ + int *np = table.lookup(s); + if (!np) { + np = new int; + *np = next_index++; + table.define(s, np); + } + return *np; +} + +static character_indexer indexer; + +int font::number_to_index(int n) +{ + return indexer.numbered_char_index(n); +} + +int font::name_to_index(const char *s) +{ + assert(s != 0 && s[0] != '\0' && s[0] != ' '); + if (s[1] == '\0') + return indexer.ascii_char_index(s[0]); + /* char128 and \200 are synonyms */ + if (s[0] == 'c' && s[1] == 'h' && s[2] == 'a' && s[3] == 'r') { + char *res; + long n = strtol(s + 4, &res, 10); + if (res != s + 4 && *res == '\0' && n >= 0 && n < 256) + return indexer.ascii_char_index((unsigned char)n); + } + return indexer.named_char_index(s); +} + diff --git a/contrib/groff/src/libs/libgroff/new.cc b/contrib/groff/src/libs/libgroff/new.cc new file mode 100644 index 0000000..8d98591 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/new.cc @@ -0,0 +1,68 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "posix.h" +#include "nonposix.h" + +extern const char *program_name; + +static void ewrite(const char *s) +{ + write(2, s, strlen(s)); +} + +void *operator new(size_t size) +{ + // Avoid relying on the behaviour of malloc(0). + if (size == 0) + size++; +#ifdef COOKIE_BUG + char *p = (char *)malloc(unsigned(size + 8)); +#else /* not COOKIE_BUG */ + char *p = (char *)malloc(unsigned(size)); +#endif /* not COOKIE_BUG */ + if (p == 0) { + if (program_name) { + ewrite(program_name); + ewrite(": "); + } + ewrite("out of memory\n"); + _exit(-1); + } +#ifdef COOKIE_BUG + ((unsigned *)p)[1] = 0; + return p + 8; +#else /* not COOKIE_BUG */ + return p; +#endif /* not COOKIE_BUG */ +} + +#ifdef COOKIE_BUG + +void operator delete(void *p) +{ + if (p) + free((void *)((char *)p - 8)); +} + +#endif /* COOKIE_BUG */ diff --git a/contrib/groff/src/libs/libgroff/prime.cc b/contrib/groff/src/libs/libgroff/prime.cc new file mode 100644 index 0000000..f0b1ead --- /dev/null +++ b/contrib/groff/src/libs/libgroff/prime.cc @@ -0,0 +1,26 @@ +#include <math.h> + +int is_prime(unsigned n) +{ + if (n <= 3) + return 1; + if (!(n & 1)) + return 0; + if (n % 3 == 0) + return 0; + unsigned lim = unsigned(sqrt((double)n)); + unsigned d = 5; + for (;;) { + if (d > lim) + break; + if (n % d == 0) + return 0; + d += 2; + if (d > lim) + break; + if (n % d == 0) + return 0; + d += 4; + } + return 1; +} diff --git a/contrib/groff/src/libs/libgroff/progname.cc b/contrib/groff/src/libs/libgroff/progname.cc new file mode 100644 index 0000000..a70e341 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/progname.cc @@ -0,0 +1 @@ +const char *program_name = 0; diff --git a/contrib/groff/src/libs/libgroff/ptable.cc b/contrib/groff/src/libs/libgroff/ptable.cc new file mode 100644 index 0000000..76735c2 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/ptable.cc @@ -0,0 +1,52 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "ptable.h" +#include "errarg.h" +#include "error.h" + +unsigned long hash_string(const char *s) +{ + assert(s != 0); + unsigned long h = 0, g; + while (*s != 0) { + h <<= 4; + h += *s++; + if ((g = h & 0xf0000000) != 0) { + h ^= g >> 24; + h ^= g; + } + } + return h; +} + +static const unsigned table_sizes[] = { +101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, +80021, 160001, 500009, 1000003, 2000003, 4000037, 8000009, +16000057, 32000011, 64000031, 128000003, 0 +}; + +unsigned next_ptable_size(unsigned n) +{ + const unsigned *p; + for (p = table_sizes; *p <= n; p++) + if (*p == 0) + fatal("cannot expand table"); + return *p; +} diff --git a/contrib/groff/src/libs/libgroff/putenv.c b/contrib/groff/src/libs/libgroff/putenv.c new file mode 100644 index 0000000..c1ca671 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/putenv.c @@ -0,0 +1,95 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* Hacked slightly by jjc@jclark.com for groff. */ + +#include <string.h> + +#ifdef __STDC__ +#include <stddef.h> +typedef void *PTR; +typedef size_t SIZE_T; +#else /* not __STDC__ */ +typedef char *PTR; +typedef int SIZE_T; +#endif /* not __STDC__ */ + +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#else /* not HAVE_STDLIB_H */ +PTR malloc(); +#endif /* not HAVE_STDLIB_H */ + +#ifndef NULL +#define NULL 0 +#endif + +extern char **environ; + +/* Put STRING, which is of the form "NAME=VALUE", in the environment. */ + +int putenv(const char *string) +{ + char *name_end = strchr(string, '='); + SIZE_T size; + char **ep; + + if (name_end == NULL) + { + /* Remove the variable from the environment. */ + size = strlen(string); + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, size) && (*ep)[size] == '=') + { + while (ep[1] != NULL) + { + ep[0] = ep[1]; + ++ep; + } + *ep = NULL; + return 0; + } + } + + size = 0; + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp(*ep, string, name_end - string) + && (*ep)[name_end - string] == '=') + break; + else + ++size; + + if (*ep == NULL) + { + static char **last_environ = NULL; + char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); + if (new_environ == NULL) + return -1; + (void) memcpy((PTR) new_environ, (PTR) environ, size * sizeof(char *)); + new_environ[size] = (char *) string; + new_environ[size + 1] = NULL; + if (last_environ != NULL) + free((PTR) last_environ); + last_environ = new_environ; + environ = new_environ; + } + else + *ep = (char *) string; + + return 0; +} diff --git a/contrib/groff/src/libs/libgroff/searchpath.cc b/contrib/groff/src/libs/libgroff/searchpath.cc new file mode 100644 index 0000000..f4e2b90 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/searchpath.cc @@ -0,0 +1,132 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#include "lib.h" +#include "searchpath.h" +#include "nonposix.h" + +search_path::search_path(const char *envvar, const char *standard, + int add_home, int add_current) +{ + char *home = 0; + if (add_home) + home = getenv("HOME"); + char *e = 0; + if (envvar) + e = getenv(envvar); + dirs = new char[((e && *e) ? strlen(e) + 1 : 0) + + (add_current ? 1 + 1 : 0) + + ((home && *home) ? strlen(home) + 1 : 0) + + ((standard && *standard) ? strlen(standard) : 0) + + 1]; + *dirs = '\0'; + if (e && *e) { + strcat(dirs, e); + strcat(dirs, PATH_SEP); + } + if (add_current) { + strcat(dirs, "."); + strcat(dirs, PATH_SEP); + } + if (home && *home) { + strcat(dirs, home); + strcat(dirs, PATH_SEP); + } + if (standard && *standard) + strcat(dirs, standard); + init_len = strlen(dirs); +} + +search_path::~search_path() +{ + // dirs is always allocated + a_delete dirs; +} + +void search_path::command_line_dir(const char *s) +{ + char *old = dirs; + unsigned old_len = strlen(old); + unsigned slen = strlen(s); + dirs = new char[old_len + 1 + slen + 1]; + memcpy(dirs, old, old_len - init_len); + char *p = dirs; + p += old_len - init_len; + if (init_len == 0) + *p++ = PATH_SEP[0]; + memcpy(p, s, slen); + p += slen; + if (init_len > 0) { + *p++ = PATH_SEP[0]; + memcpy(p, old + old_len - init_len, init_len); + p += init_len; + } + *p++ = '\0'; + a_delete old; +} + +FILE *search_path::open_file(const char *name, char **pathp) +{ + assert(name != 0); + if (IS_ABSOLUTE(name) || *dirs == '\0') { + FILE *fp = fopen(name, "r"); + if (fp) { + if (pathp) + *pathp = strsave(name); + return fp; + } + else + return 0; + } + unsigned namelen = strlen(name); + char *p = dirs; + for (;;) { + char *end = strchr(p, PATH_SEP[0]); + if (!end) + end = strchr(p, '\0'); + int need_slash = end > p && strchr(DIR_SEPS, end[-1]) == 0; + char *path = new char[(end - p) + need_slash + namelen + 1]; + memcpy(path, p, end - p); + if (need_slash) + path[end - p] = '/'; + strcpy(path + (end - p) + need_slash, name); +#if 0 + fprintf(stderr, "trying `%s'\n", path); +#endif + FILE *fp = fopen(path, "r"); + if (fp) { + if (pathp) + *pathp = path; + else + a_delete path; + return fp; + } + a_delete path; + if (*end == '\0') + break; + p = end + 1; + } + return 0; +} diff --git a/contrib/groff/src/libs/libgroff/strerror.c b/contrib/groff/src/libs/libgroff/strerror.c new file mode 100644 index 0000000..69089f1 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/strerror.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> + +#define INT_DIGITS 19 /* enough for 64 bit integer */ + +#ifndef HAVE_SYS_NERR +extern int sys_nerr; +#endif +#ifndef HAVE_SYS_ERRLIST +extern char *sys_errlist[]; +#endif + +char *strerror(n) + int n; +{ + static char buf[sizeof("Error ") + 1 + INT_DIGITS]; + if (n >= 0 && n < sys_nerr && sys_errlist[n] != 0) + return sys_errlist[n]; + else { + sprintf(buf, "Error %d", n); + return buf; + } +} diff --git a/contrib/groff/src/libs/libgroff/string.cc b/contrib/groff/src/libs/libgroff/string.cc new file mode 100644 index 0000000..4bcd4cc --- /dev/null +++ b/contrib/groff/src/libs/libgroff/string.cc @@ -0,0 +1,311 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include "stringclass.h" +#include "lib.h" + +static char *salloc(int len, int *sizep); +static void sfree(char *ptr, int size); +static char *sfree_alloc(char *ptr, int size, int len, int *sizep); +static char *srealloc(char *ptr, int size, int oldlen, int newlen, int *sizep); + +static char *salloc(int len, int *sizep) +{ + if (len == 0) { + *sizep = 0; + return 0; + } + else + return new char[*sizep = len*2]; +} + +static void sfree(char *ptr, int) +{ + a_delete ptr; +} + +static char *sfree_alloc(char *ptr, int oldsz, int len, int *sizep) +{ + if (oldsz >= len) { + *sizep = oldsz; + return ptr; + } + a_delete ptr; + if (len == 0) { + *sizep = 0; + return 0; + } + else + return new char[*sizep = len*2]; +} + +static char *srealloc(char *ptr, int oldsz, int oldlen, int newlen, int *sizep) +{ + if (oldsz >= newlen) { + *sizep = oldsz; + return ptr; + } + if (newlen == 0) { + a_delete ptr; + *sizep = 0; + return 0; + } + else { + char *p = new char[*sizep = newlen*2]; + if (oldlen < newlen && oldlen != 0) + memcpy(p, ptr, oldlen); + a_delete ptr; + return p; + } +} + +string::string() : ptr(0), len(0), sz(0) +{ +} + +string::string(const char *p, int n) : len(n) +{ + assert(n >= 0); + ptr = salloc(n, &sz); + if (n != 0) + memcpy(ptr, p, n); +} + +string::string(const char *p) +{ + if (p == 0) { + len = 0; + ptr = 0; + sz = 0; + } + else { + len = strlen(p); + ptr = salloc(len, &sz); + memcpy(ptr, p, len); + } +} + +string::string(char c) : len(1) +{ + ptr = salloc(1, &sz); + *ptr = c; +} + +string::string(const string &s) : len(s.len) +{ + ptr = salloc(len, &sz); + if (len != 0) + memcpy(ptr, s.ptr, len); +} + +string::~string() +{ + sfree(ptr, sz); +} + +string &string::operator=(const string &s) +{ + ptr = sfree_alloc(ptr, sz, s.len, &sz); + len = s.len; + if (len != 0) + memcpy(ptr, s.ptr, len); + return *this; +} + +string &string::operator=(const char *p) +{ + if (p == 0) { + sfree(ptr, len); + len = 0; + ptr = 0; + sz = 0; + } + else { + int slen = strlen(p); + ptr = sfree_alloc(ptr, sz, slen, &sz); + len = slen; + memcpy(ptr, p, len); + } + return *this; +} + +string &string::operator=(char c) +{ + ptr = sfree_alloc(ptr, sz, 1, &sz); + len = 1; + *ptr = c; + return *this; +} + +void string::move(string &s) +{ + sfree(ptr, sz); + ptr = s.ptr; + len = s.len; + sz = s.sz; + s.ptr = 0; + s.len = 0; + s.sz = 0; +} + +void string::grow1() +{ + ptr = srealloc(ptr, sz, len, len + 1, &sz); +} + +string &string::operator+=(const char *p) +{ + if (p != 0) { + int n = strlen(p); + int newlen = len + n; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, p, n); + len = newlen; + } + return *this; +} + +string &string::operator+=(const string &s) +{ + if (s.len != 0) { + int newlen = len + s.len; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, s.ptr, s.len); + len = newlen; + } + return *this; +} + +void string::append(const char *p, int n) +{ + if (n > 0) { + int newlen = len + n; + if (newlen > sz) + ptr = srealloc(ptr, sz, len, newlen, &sz); + memcpy(ptr + len, p, n); + len = newlen; + } +} + +string::string(const char *s1, int n1, const char *s2, int n2) +{ + assert(n1 >= 0 && n2 >= 0); + len = n1 + n2; + if (len == 0) { + sz = 0; + ptr = 0; + } + else { + ptr = salloc(len, &sz); + if (n1 == 0) + memcpy(ptr, s2, n2); + else { + memcpy(ptr, s1, n1); + if (n2 != 0) + memcpy(ptr + n1, s2, n2); + } + } +} + +int operator<=(const string &s1, const string &s2) +{ + return (s1.len <= s2.len + ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 + : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); +} + +int operator<(const string &s1, const string &s2) +{ + return (s1.len < s2.len + ? s1.len == 0 || memcmp(s1.ptr, s2.ptr, s1.len) <= 0 + : s2.len != 0 && memcmp(s1.ptr, s2.ptr, s2.len) < 0); +} + +int operator>=(const string &s1, const string &s2) +{ + return (s1.len >= s2.len + ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 + : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); +} + +int operator>(const string &s1, const string &s2) +{ + return (s1.len > s2.len + ? s2.len == 0 || memcmp(s1.ptr, s2.ptr, s2.len) >= 0 + : s1.len != 0 && memcmp(s1.ptr, s2.ptr, s1.len) > 0); +} + +void string::set_length(int i) +{ + assert(i >= 0); + if (i > sz) + ptr = srealloc(ptr, sz, len, i, &sz); + len = i; +} + +void string::clear() +{ + len = 0; +} + +int string::search(char c) const +{ + char *p = ptr ? (char *)memchr(ptr, c, len) : NULL; + return p ? p - ptr : -1; +} + +// we silently strip nuls + +char *string::extract() const +{ + char *p = ptr; + int n = len; + int nnuls = 0; + int i; + for (i = 0; i < n; i++) + if (p[i] == '\0') + nnuls++; + char *q = new char[n + 1 - nnuls]; + char *r = q; + for (i = 0; i < n; i++) + if (p[i] != '\0') + *r++ = p[i]; + q[n] = '\0'; + return q; +} + +void put_string(const string &s, FILE *fp) +{ + int len = s.length(); + const char *ptr = s.contents(); + for (int i = 0; i < len; i++) + putc(ptr[i], fp); +} + +string as_string(int i) +{ + static char buf[INT_DIGITS + 2]; + sprintf(buf, "%d", i); + return string(buf); +} + diff --git a/contrib/groff/src/libs/libgroff/strsave.cc b/contrib/groff/src/libs/libgroff/strsave.cc new file mode 100644 index 0000000..dfd2b6f --- /dev/null +++ b/contrib/groff/src/libs/libgroff/strsave.cc @@ -0,0 +1,31 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <string.h> + +char *strsave(const char *s) +{ + if (s == 0) + return 0; + char *p = new char[strlen(s) + 1]; + strcpy(p, s); + return p; +} + diff --git a/contrib/groff/src/libs/libgroff/strtol.c b/contrib/groff/src/libs/libgroff/strtol.c new file mode 100644 index 0000000..61ce70e --- /dev/null +++ b/contrib/groff/src/libs/libgroff/strtol.c @@ -0,0 +1,128 @@ +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#ifndef LONG_MAX +#define LONG_MAX 2147483647 +#endif + +#ifndef LONG_MIN +#define LONG_MIN (-LONG_MAX-1) +#endif + +#ifdef isascii +#define ISASCII(c) isascii(c) +#else +#define ISASCII(c) (1) +#endif + +long strtol(str, ptr, base) + char *str, **ptr; + int base; +{ + char *start = str; + int neg = 0; + long val; + char *p; + static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + + while (ISASCII((unsigned char)*str) && isspace((unsigned char)*str)) + str++; + + if (*str == '-') { + neg = 1; + str++; + } + if (base == 0) { + if (*str == '0') { + if (str[1] == 'x' || str[1] == 'X') { + str += 2; + base = 16; + } + else + base = 8; + } + else + base = 10; + } + if (base < 2 || base > 36) + base = 10; + else if (base == 16 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + + p = strchr(digits, (ISASCII((unsigned char)*str) + && isupper((unsigned char)*str) + ? tolower((unsigned char)*str) + : *str)); + if (p == 0 || (val = (p - digits)) >= base) { + if (base == 16 && str > start && (str[-1] == 'x' || str[-1] == 'X')) { + if (ptr) + *ptr = str - 1; + } + else { + if (ptr) + *ptr = start; + errno = ERANGE; + } + return 0; + } + if (neg) + val = -val; + + while (*++str != '\0') { + int n; + + p = strchr(digits, (ISASCII((unsigned char)*str) + && isupper((unsigned char)*str) + ? tolower((unsigned char)*str) : *str)); + if (p == 0) + break; + n = p - digits; + if (n >= base) + break; + if (neg) { + if (-(unsigned long)val > (-(unsigned long)LONG_MIN - n)/base) { + val = LONG_MIN; + errno = ERANGE; + } + else + val = val*base - n; + } + else { + if (val > (LONG_MAX - n)/base) { + val = LONG_MAX; + errno = ERANGE; + } + else + val = val*base + n; + } + } + + if (ptr) + *ptr = str; + + return val; +} diff --git a/contrib/groff/src/libs/libgroff/tmpfile.cc b/contrib/groff/src/libs/libgroff/tmpfile.cc new file mode 100644 index 0000000..a6c2010 --- /dev/null +++ b/contrib/groff/src/libs/libgroff/tmpfile.cc @@ -0,0 +1,186 @@ +// -*- C++ -*- +/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc. + Written by James Clark (jjc@jclark.com) + +This file is part of groff. + +groff 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, or (at your option) any later +version. + +groff 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> + +#include "posix.h" +#include "lib.h" +#include "errarg.h" +#include "error.h" +#include "nonposix.h" + +extern "C" { + // Solaris 2.5.1 has these functions, + // but its stdlib.h fails to declare them. + char *mktemp(char *); + int mkstemp(char *); +} + +// If this is set, create temporary files there +#define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR" +// otherwise if this is set, create temporary files there +#define TMPDIR_ENVVAR "TMPDIR" +// otherwise if P_tmpdir is defined, create temporary files there +#ifdef P_tmpdir +# define DEFAULT_TMPDIR P_tmpdir +#else +// otherwise create temporary files here. +# define DEFAULT_TMPDIR "/tmp" +#endif +// Use this as the prefix for temporary filenames. +#define TMPFILE_PREFIX "groff" + +/* + * Generate a temporary name template with a postfix + * immediately after the TMPFILE_PREFIX. + * It uses the groff preferences for a temporary directory. + * Note that no file name is either created or opened, + * only the *template* is returned. + */ + +char *xtmptemplate(char *postfix) +{ + const char *dir = getenv(GROFF_TMPDIR_ENVVAR); + int postlen = 0; + + if (postfix) + postlen = strlen(postfix); + + if (!dir) { + dir = getenv(TMPDIR_ENVVAR); + if (!dir) + dir = DEFAULT_TMPDIR; + } + + size_t dir_len = strlen(dir); + const char *dir_end = dir + dir_len - 1; + int needs_slash = strchr(DIR_SEPS, *dir_end) == NULL; + char *templ = new char[strlen(dir) + needs_slash + + sizeof(TMPFILE_PREFIX) - 1 + 6 + 1 + postlen]; + strcpy(templ, dir); + if (needs_slash) + strcat(templ, "/"); + strcat(templ, TMPFILE_PREFIX); + if (postlen > 0) + strcat(templ, postfix); + strcat(templ, "XXXXXX"); + + return( templ ); +} + +// The trick with unlinking the temporary file while it is still in +// use is not portable, it will fail on MS-DOS and most MS-Windows +// filesystems. So it cannot be used on non-Posix systems. +// Instead, we maintain a list of files to be deleted on exit, and +// register an atexit function that will remove them all in one go. +// This should be portable to all platforms. + +static struct xtmpfile_list { + struct xtmpfile_list *next; + char fname[1]; +} *xtmpfiles_to_delete; + +static void remove_tmp_files() +{ + struct xtmpfile_list *p = xtmpfiles_to_delete; + + while (p) + { + if (unlink(p->fname) < 0) + error("cannot unlink `%1': %2", p->fname, strerror(errno)); + struct xtmpfile_list *old = p; + p = p->next; + free(old); + } +} + +static void add_tmp_file(const char *name) +{ + if (xtmpfiles_to_delete == NULL) + atexit(remove_tmp_files); + + struct xtmpfile_list *p + = (struct xtmpfile_list *)malloc(sizeof(struct xtmpfile_list) + + strlen (name)); + if (p == NULL) + { + error("cannot unlink `%1': %2", name, strerror(errno)); + return; + } + p->next = xtmpfiles_to_delete; + strcpy(p->fname, name); + xtmpfiles_to_delete = p; +} + +// Open a temporary file and with fatal error on failure. + +#ifndef _MSC_VER + +FILE *xtmpfile(char **namep, char *postfix, int do_unlink) +{ + char *templ = xtmptemplate(postfix); + +#ifdef HAVE_MKSTEMP + errno = 0; + int fd = mkstemp(templ); + if (fd < 0) + fatal("cannot create temporary file: %1", strerror(errno)); + errno = 0; + FILE *fp = fdopen(fd, FOPEN_RWB); // many callers of xtmpfile use binary I/O + if (!fp) + fatal("fdopen: %1", strerror(errno)); +#else /* not HAVE_MKSTEMP */ + if (!mktemp(templ) || !templ[0]) + fatal("cannot create file name for temporary file"); + errno = 0; + FILE *fp = fopen(templ, FOPEN_RWB); + if (!fp) + fatal("cannot open `%1': %2", templ, strerror(errno)); +#endif /* not HAVE_MKSTEMP */ + if (do_unlink) + add_tmp_file(templ); + if ((namep != 0) && ((*namep) != 0)) { + *namep = templ; + } else { + a_delete templ; + } + return fp; +} + +#else + +// FIXME: does MSVC have mktemp or mkstemp? If so, it should now +// use the version above, as it no longer removes an open file. +// The version below will NOT work with grohtml, since grohtml +// wants to know the name of the file opened by xtmpfile!! + +// If you're not running Unix, the following will do: +FILE *xtmpfile(char **namep, char *postfix, int do_unlink) +{ + FILE *fp = tmpfile(); + if (!fp) + fatal("couldn't create temporary file"); + return fp; +} + +#endif /* _MSC_VER */ |