├── .gitignore ├── LICENSE ├── Makefile.am ├── README ├── build-aux └── .gitignore ├── configure.ac ├── examples ├── Makefile.am ├── basename.c ├── calc.c ├── cref.c ├── double.c ├── getword.c ├── getword.h ├── idents.c ├── ids.c ├── integer.c ├── integer.h ├── iref.c ├── kref.c ├── mpcalc.c ├── sieve.c ├── sort.c ├── spin.c ├── wf.c ├── words.c └── xref.c ├── include ├── Makefile.am ├── ap.h ├── arena.h ├── arith.h ├── array.h ├── arrayrep.h ├── assert.h ├── atom.h ├── bit.h ├── chan.h ├── except.h ├── fmt.h ├── list.h ├── mem.h ├── mp.h ├── ring.h ├── sem.h ├── seq.h ├── set.h ├── stack.h ├── str.h ├── table.h ├── text.h ├── thread.h └── xp.h ├── install.html ├── makefile.nt ├── misc ├── Makefile.am ├── custom.mk.old ├── makefile.old └── maxalign.c └── src ├── Makefile.am ├── ap.c ├── arena.c ├── arith.c ├── array.c ├── assert.c ├── atom.c ├── bit.c ├── chan.c ├── except.c ├── fmt.c ├── libcii.def ├── list.c ├── mem.c ├── memchk.c ├── memcmp.c ├── memmove.c ├── mp.c ├── ring.c ├── seq.c ├── set.c ├── stack.c ├── str.c ├── strerror.c ├── strncmp.c ├── swtch.s ├── table.c ├── text.c ├── thread-nt.c ├── thread.c └── xp.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.slo 2 | *.lo 3 | *.o 4 | *.so 5 | *.lai 6 | *.la 7 | *.a 8 | *.obj 9 | *.exe 10 | *.lib 11 | 12 | Makefile 13 | Makefile.in 14 | .deps 15 | .libs 16 | 17 | # http://www.gnu.org/software/autoconf 18 | # Check build-aux/.gitignore for the commented stuff 19 | /autom4te.cache 20 | /aclocal.m4 21 | /compile 22 | /configure 23 | /depcomp 24 | /install-sh 25 | /missing 26 | /config.guess 27 | /config.log 28 | /config.status 29 | /config.sub 30 | /config.h 31 | /config.h.in 32 | /stamp-h1 33 | 34 | # libtool 35 | build-aux/ltmain.sh 36 | /libtool 37 | m4/libtool.m4 38 | m4/ltoptions.m4 39 | m4/ltsugar.m4 40 | m4/ltversion.m4 41 | m4/lt~obsolete.m4 42 | 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 1994,1995,1996,1997 by David R. Hanson. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 4 | software and associated documentation files (the "Software"), to deal in the Software 5 | without restriction, including without limitation the rights to use, copy, modify, 6 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 7 | permit persons to whom the Software is furnished to do so, subject to the following 8 | conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies 11 | or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 14 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 15 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 16 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 17 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 18 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | 21 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | SUBDIRS = src include misc examples 3 | 4 | EXTRA_DIST = makefile.nt 5 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This hierarchy contains all the source code from my book 2 | "C Interfaces and Implementations: Techniques for Creating Reusable 3 | Software (Addison-Wesley Professional Computing Series, 1997, 4 | ISBN 0-201-49841-3). 5 | 6 | For installation instructions, see install.html. 7 | 8 | For a summary of the distribution's revision history see 9 | see http://code.google.com/p/cii/w/list 10 | 11 | For the history of versions before 1.2, see 12 | http://cii.googlecode.com/svn/tags/v12/history.html 13 | 14 | For more information, visit http://www.cs.princeton.edu/software/cii/. 15 | ----- 16 | David R. Hanson 17 | drh at drhanson.net / http://drh.home.dyndns.org/ 18 | -------------------------------------------------------------------------------- /build-aux/.gitignore: -------------------------------------------------------------------------------- 1 | /config.guess 2 | /config.sub 3 | /depcomp 4 | /install-sh 5 | /missing 6 | /compile 7 | 8 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.61]) 5 | 6 | AC_INIT([libcii],[2.0],[kevin.bowling@kev009.com]) 7 | 8 | AC_CONFIG_AUX_DIR([build-aux]) 9 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 10 | LT_PREREQ([2.2]) 11 | AC_CONFIG_MACRO_DIR([m4]) 12 | 13 | # Don't look for C++ or Fortran compilers 14 | 15 | m4_undefine([AC_PROG_F77]) 16 | m4_defun([AC_PROG_F77],[]) 17 | 18 | LT_INIT 19 | AC_SUBST(LIBTOOL_DEPS) 20 | 21 | AC_CONFIG_SRCDIR([src/text.c]) 22 | AC_CONFIG_HEADERS([config.h]) 23 | 24 | # Checks for programs. 25 | AC_PROG_CC 26 | 27 | # Checks for libraries. 28 | 29 | # Checks for header files. 30 | AC_CHECK_HEADERS([float.h limits.h stddef.h stdlib.h string.h sys/time.h]) 31 | 32 | # Checks for typedefs, structures, and compiler characteristics. 33 | AC_TYPE_SIZE_T 34 | 35 | # Checks for library functions. 36 | AC_FUNC_MALLOC 37 | AC_FUNC_REALLOC 38 | AC_CHECK_FUNCS([memchr memmove memset strchr strerror]) 39 | 40 | AC_CONFIG_FILES([Makefile src/Makefile include/Makefile examples/Makefile 41 | misc/Makefile]) 42 | 43 | AC_OUTPUT 44 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | #bin_PROGRAMS = jupiter 2 | #examples_SOURCES = main.c 3 | #examples_CPPFLAGS = -I$(top_srcdir)/include 4 | #examples_LDADD = ../src/libcii.la 5 | -------------------------------------------------------------------------------- /examples/basename.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fmt.h" 3 | #include "str.h" 4 | 5 | char *dirname(char *path, int i, int j) { 6 | if ((j = Str_rchr(path, i, j, '/')) > 0) 7 | return Str_dup(path, i, j + 1, 1); 8 | else 9 | return Str_dup("./", 1, 0, 1); 10 | } 11 | 12 | char *basename(char *path, int i, int j, const char *suffix) { 13 | i = Str_rchr(path, i, j, '/'); 14 | j = Str_rmatch(path, i + 1, 0, suffix); 15 | return Str_dup(path, i + 1, j, 1); 16 | } 17 | 18 | int main(int argc, char *argv[]) { 19 | int i; 20 | 21 | if (Str_find(argv[0], 1, 0, "dirname") > 0) 22 | for (i = 1; i < argc; i += 2) 23 | Fmt_print("%s\n", dirname(argv[i], 1, 0)); 24 | else 25 | for (i = 1; i < argc; i += 2) 26 | Fmt_print("%s\n", basename(argv[i], 1, 0, i+1 < argc ? argv[i+1] : "")); 27 | return EXIT_SUCCESS; 28 | } 29 | -------------------------------------------------------------------------------- /examples/calc.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "stack.h" 7 | #include "ap.h" 8 | #include "fmt.h" 9 | Stack_T sp; 10 | AP_T pop(void) { 11 | if (!Stack_empty(sp)) 12 | return Stack_pop(sp); 13 | else { 14 | Fmt_fprint(stderr, "?stack underflow\n"); 15 | return AP_new(0); 16 | } 17 | } 18 | int main(int argc, char *argv[]) { 19 | int c; 20 | sp = Stack_new(); 21 | Fmt_register('D', AP_fmt); 22 | while ((c = getchar()) != EOF) 23 | switch (c) { 24 | case ' ': case '\t': case '\n': case '\f': case '\r': 25 | break; 26 | case '0': case '1': case '2': case '3': case '4': 27 | case '5': case '6': case '7': case '8': case '9': { 28 | char buf[512]; 29 | { 30 | int i = 0; 31 | for ( ; c != EOF && isdigit(c); c = getchar(), i++) 32 | if (i < (int)sizeof (buf) - 1) 33 | buf[i] = c; 34 | if (i > (int)sizeof (buf) - 1) { 35 | i = (int)sizeof (buf) - 1; 36 | Fmt_fprint(stderr, 37 | "?integer constant exceeds %d digits\n", i); 38 | } 39 | buf[i] = 0; 40 | if (c != EOF) 41 | ungetc(c, stdin); 42 | } 43 | Stack_push(sp, AP_fromstr(buf, 10, NULL)); 44 | break; 45 | } 46 | case '+': { 47 | AP_T y = pop(), x = pop(); 48 | Stack_push(sp, AP_add(x, y)); 49 | AP_free(&x); 50 | AP_free(&y); 51 | break; 52 | } 53 | case '-': { 54 | AP_T y = pop(), x = pop(); 55 | Stack_push(sp, AP_sub(x, y)); 56 | AP_free(&x); 57 | AP_free(&y); 58 | break; 59 | } 60 | case '*': { 61 | AP_T y = pop(), x = pop(); 62 | Stack_push(sp, AP_mul(x, y)); 63 | AP_free(&x); 64 | AP_free(&y); 65 | break; 66 | } 67 | case '/': { 68 | AP_T y = pop(), x = pop(); 69 | if (AP_cmpi(y, 0) == 0) { 70 | Fmt_fprint(stderr, "?/ by 0\n"); 71 | Stack_push(sp, AP_new(0)); 72 | } else 73 | Stack_push(sp, AP_div(x, y)); 74 | AP_free(&x); 75 | AP_free(&y); 76 | break; 77 | } 78 | case '%': { 79 | AP_T y = pop(), x = pop(); 80 | if (AP_cmpi(y, 0) == 0) { 81 | Fmt_fprint(stderr, "?%% by 0\n"); 82 | Stack_push(sp, AP_new(0)); 83 | } else 84 | Stack_push(sp, AP_mod(x, y)); 85 | AP_free(&x); 86 | AP_free(&y); 87 | break; 88 | } 89 | case '^': { 90 | AP_T y = pop(), x = pop(); 91 | if (AP_cmpi(y, 0) <= 0) { 92 | Fmt_fprint(stderr, "?nonpositive power\n"); 93 | Stack_push(sp, AP_new(0)); 94 | } else 95 | Stack_push(sp, AP_pow(x, y, NULL)); 96 | AP_free(&x); 97 | AP_free(&y); 98 | break; 99 | } 100 | case 'd': { 101 | AP_T x = pop(); 102 | Stack_push(sp, x); 103 | Stack_push(sp, AP_addi(x, 0)); 104 | break; 105 | } 106 | case 'p': { 107 | AP_T x = pop(); 108 | Fmt_print("%D\n", x); 109 | Stack_push(sp, x); 110 | break; 111 | } 112 | case 'f': 113 | if (!Stack_empty(sp)) { 114 | Stack_T tmp = Stack_new(); 115 | while (!Stack_empty(sp)) { 116 | AP_T x = pop(); 117 | Fmt_print("%D\n", x); 118 | Stack_push(tmp, x); 119 | } 120 | while (!Stack_empty(tmp)) 121 | Stack_push(sp, Stack_pop(tmp)); 122 | Stack_free(&tmp); 123 | } 124 | break; 125 | case '~': { 126 | AP_T x = pop(); 127 | Stack_push(sp, AP_neg(x)); 128 | AP_free(&x); 129 | break; 130 | } 131 | case 'c': while (!Stack_empty(sp)) { 132 | AP_T x = Stack_pop(sp); 133 | AP_free(&x); 134 | } break; 135 | case 'q': while (!Stack_empty(sp)) { 136 | AP_T x = Stack_pop(sp); 137 | AP_free(&x); 138 | } 139 | Stack_free(&sp); 140 | return EXIT_SUCCESS; 141 | default: 142 | if (isprint(c)) 143 | Fmt_fprint(stderr, "?'%c'", c); 144 | else 145 | Fmt_fprint(stderr, "?'\\%03o'", c); 146 | Fmt_fprint(stderr, " is unimplemented\n"); 147 | break; 148 | } 149 | while (!Stack_empty(sp)) { 150 | AP_T x = Stack_pop(sp); 151 | AP_free(&x); 152 | } 153 | Stack_free(&sp); 154 | return EXIT_SUCCESS; 155 | } 156 | -------------------------------------------------------------------------------- /examples/cref.c: -------------------------------------------------------------------------------- 1 | /* 2 | This version of xref uses the Text and Ring interfaces. 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "assert.h" 9 | #include "fmt.h" 10 | #include "mem.h" 11 | #include "table.h" 12 | #include "integer.h" 13 | #include "ring.h" 14 | #include "text.h" 15 | 16 | static char rcsid[] = "$Id$"; 17 | 18 | Text_T getword(Text_T *line, Text_T first, Text_T rest) { 19 | int i, j; 20 | 21 | assert(line); 22 | if ((i = Text_upto(*line, 1, 0, first)) > 0) { 23 | Text_T word = Text_sub(*line, j = Text_many(*line, i, 0, rest), i); 24 | *line = Text_sub(*line, j, 0); 25 | return word; 26 | } else 27 | return Text_null; 28 | } 29 | 30 | Text_T first, rest; 31 | 32 | int textcmp(const void *x, const void *y) { 33 | return Text_cmp(*(Text_T *)x, *(Text_T *)y); 34 | } 35 | 36 | int compare(const void *x, const void *y) { 37 | return textcmp(*(Text_T **)x, *(Text_T **)y); 38 | } 39 | 40 | unsigned texthash(const void *x) { 41 | int i; 42 | unsigned h = 0; 43 | const Text_T *t = x; 44 | 45 | for (i = 0; i < t->len; i++) 46 | h = (h<<1) + t->str[i]; 47 | return h; 48 | } 49 | 50 | void print(Table_T files) { 51 | int i; 52 | 53 | void **array = Table_toArray(files, NULL); 54 | qsort(array, Table_length(files), 2*sizeof (*array), compare); 55 | for (i = 0; array[i]; i += 2) { 56 | Ring_T ring = array[i+1]; 57 | Text_T *filename = array[i]; 58 | if (filename->len > 0) 59 | Fmt_print("\t%T:", filename); 60 | while (Ring_length(ring) > 0) { 61 | Integer_T line = Ring_remhi(ring); 62 | Fmt_print(" %D", line); 63 | FREE(line); 64 | } 65 | Fmt_print("\n"); 66 | FREE(filename); 67 | Ring_free(&ring); 68 | } 69 | FREE(array); 70 | Table_free(&files); 71 | } 72 | 73 | Text_T *copy(Text_T t) { 74 | Text_T *p; 75 | 76 | NEW(p); 77 | *p = t; 78 | return p; 79 | } 80 | 81 | void cref(char *name, FILE *fp, Table_T identifiers) { 82 | char buf[512]; 83 | Text_T filename = { 0, "" }; 84 | int linenum; 85 | 86 | if (name) 87 | filename = Text_put(name); 88 | for (linenum = 1; fgets(buf, sizeof buf, fp) != NULL; linenum++) { 89 | Text_T id, line = Text_put(buf); 90 | while ((id = getword(&line, first, rest)).len > 0) { 91 | Ring_T ring; 92 | Table_T files; 93 | files = Table_get(identifiers, &id); 94 | if (files == NULL) { 95 | files = Table_new(0, textcmp, texthash); 96 | Table_put(identifiers, copy(id), files); 97 | } 98 | ring = Table_get(files, &filename); 99 | if (ring == NULL) { 100 | ring = Ring_new(); 101 | Table_put(files, copy(filename), ring); 102 | Ring_addlo(ring, Integer_new(linenum)); 103 | } else if (Integer_get(Ring_get(ring, 0)) != linenum) 104 | Ring_addlo(ring, Integer_new(linenum)); 105 | } 106 | } 107 | } 108 | 109 | int main(int argc, char *argv[]) { 110 | int i; 111 | Table_T identifiers = Table_new(10000, textcmp, texthash); 112 | Text_save_T mark = Text_save(); 113 | 114 | Fmt_register('T', Text_fmt); 115 | Fmt_register('D', Integer_fmt); 116 | first = Text_cat(Text_cat(Text_ucase, Text_lcase), Text_box("_", 1)); 117 | rest = Text_cat(first, Text_digits); 118 | for (i = 1; i < argc; i++) { 119 | FILE *fp = fopen(argv[i], "r"); 120 | if (fp == NULL) 121 | fprintf(stderr, "%s: can't open '%s' (%s)\n", argv[0], argv[i], strerror(errno)); 122 | else { 123 | cref(argv[i], fp, identifiers); 124 | fclose(fp); 125 | } 126 | } 127 | if (argc == 1) 128 | cref(NULL, stdin, identifiers); 129 | { 130 | int i; 131 | void **array = Table_toArray(identifiers, NULL); 132 | qsort(array, Table_length(identifiers), 2*sizeof (*array), compare); 133 | for (i = 0; array[i]; i += 2) { 134 | Fmt_print("%T", array[i]); 135 | print(array[i+1]); 136 | FREE(array[i]); 137 | } 138 | FREE(array); 139 | Table_free(&identifiers); 140 | } 141 | Text_restore(&mark); 142 | return EXIT_SUCCESS; 143 | } 144 | -------------------------------------------------------------------------------- /examples/double.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | int linenum; 8 | int getword(FILE *, char *, int); 9 | void doubleword(char *, FILE *); 10 | int main(int argc, char *argv[]) { 11 | int i; 12 | for (i = 1; i < argc; i++) { 13 | FILE *fp = fopen(argv[i], "r"); 14 | if (fp == NULL) { 15 | fprintf(stderr, "%s: can't open '%s' (%s)\n", 16 | argv[0], argv[i], strerror(errno)); 17 | return EXIT_FAILURE; 18 | } else { 19 | doubleword(argv[i], fp); 20 | fclose(fp); 21 | } 22 | } 23 | if (argc == 1) doubleword(NULL, stdin); 24 | return EXIT_SUCCESS; 25 | } 26 | int getword(FILE *fp, char *buf, int size) { 27 | int c; 28 | c = getc(fp); 29 | for ( ; c != EOF && isspace(c); c = getc(fp)) 30 | if (c == '\n') 31 | linenum++; 32 | { 33 | int i = 0; 34 | for ( ; c != EOF && !isspace(c); c = getc(fp)) 35 | if (i < size - 1) 36 | buf[i++] = tolower(c); 37 | if (i < size) 38 | buf[i] = '\0'; 39 | } 40 | if (c != EOF) 41 | ungetc(c, fp); 42 | return buf[0] != '\0'; 43 | } 44 | void doubleword(char *name, FILE *fp) { 45 | char prev[128], word[128]; 46 | linenum = 1; 47 | prev[0] = '\0'; 48 | while (getword(fp, word, sizeof word)) { 49 | if (isalpha(word[0]) && strcmp(prev, word)==0) 50 | { 51 | if (name) 52 | printf("%s:", name); 53 | printf("%d: %s\n", linenum, word); 54 | } 55 | strcpy(prev, word); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/getword.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include "assert.h" 6 | #include "getword.h" 7 | int getword(FILE *fp, char *buf, int size, 8 | int first(int c), int rest(int c)) { 9 | int i = 0, c; 10 | assert(fp && buf && size > 1 && first && rest); 11 | c = getc(fp); 12 | for ( ; c != EOF; c = getc(fp)) 13 | if (first(c)) { 14 | { 15 | if (i < size - 1) 16 | buf[i++] = c; 17 | } 18 | c = getc(fp); 19 | break; 20 | } 21 | for ( ; c != EOF && rest(c); c = getc(fp)) 22 | { 23 | if (i < size - 1) 24 | buf[i++] = c; 25 | } 26 | if (i < size) 27 | buf[i] = '\0'; 28 | else 29 | buf[size-1] = '\0'; 30 | if (c != EOF) 31 | ungetc(c, fp); 32 | return i > 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/getword.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #include 3 | extern int getword(FILE *fp, char *buf, int size, 4 | int first(int c), int rest(int c)); 5 | -------------------------------------------------------------------------------- /examples/idents.c: -------------------------------------------------------------------------------- 1 | /* 2 | This version of ids uses Str and Seq, 3 | and reads the identifers from right to left. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include "fmt.h" 9 | #include "seq.h" 10 | #include "str.h" 11 | 12 | int main(int argc, char *argv[]) { 13 | char line[512]; 14 | Seq_T seq = Seq_new(1); 15 | char *first = Str_catv("abcdefghijklmnopqrstuvwxyz", 1, 0, 16 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1, 0, "_", 1, 0, NULL); 17 | char *rest = Str_cat("0123456789", 1, 0, first, 1, 0); 18 | 19 | Fmt_register('S', Str_fmt); 20 | while (fgets(line, sizeof line, stdin) != NULL) { 21 | int i, j = 0; 22 | while ((j = Str_rupto(line, 1, j, first)) > 0){ 23 | i = Str_rmany(line, 1, j + 1, rest); 24 | Seq_addlo(seq, Str_sub(line, i, j + 1)); 25 | j = i; 26 | } 27 | while (Seq_length(seq) > 0) { 28 | char *id = Seq_remlo(seq); 29 | Fmt_print("%S\n", id, 1, 0); 30 | FREE(id); 31 | } 32 | } 33 | FREE(first); FREE(rest); 34 | Seq_free(&seq); 35 | return EXIT_SUCCESS; 36 | } 37 | -------------------------------------------------------------------------------- /examples/ids.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "fmt.h" 5 | #include "str.h" 6 | int main(int argc, char *argv[]) { 7 | char line[512]; 8 | static char set[] = "0123456789_" 9 | "abcdefghijklmnopqrstuvwxyz" 10 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 11 | Fmt_register('S', Str_fmt); 12 | while (fgets(line, sizeof line, stdin) != NULL) { 13 | int i = 1, j; 14 | while ((i = Str_upto(line, i, 0, &set[10])) > 0){ 15 | j = Str_many(line, i, 0, set); 16 | Fmt_print("%S\n", line, i, j); 17 | i = j; 18 | } 19 | } 20 | return EXIT_SUCCESS; 21 | } 22 | -------------------------------------------------------------------------------- /examples/integer.c: -------------------------------------------------------------------------------- 1 | #include "fmt.h" 2 | #include "assert.h" 3 | #include "mem.h" 4 | 5 | #define T Integer_T 6 | typedef int *T; 7 | 8 | T Integer_new(int n) { 9 | T integer; 10 | 11 | NEW(integer); 12 | *integer = n; 13 | return integer; 14 | } 15 | 16 | int Integer_get(T integer) { 17 | assert(integer); 18 | return *integer; 19 | } 20 | 21 | int Integer_put(T integer, int n) { 22 | int prev; 23 | 24 | assert(integer); 25 | prev = *integer; 26 | *integer = n; 27 | return prev; 28 | } 29 | 30 | int Integer_cmp(T i1, T i2) { 31 | assert(i1); 32 | assert(i2); 33 | if (*i1 < *i2) 34 | return -1; 35 | else if (*i1 > *i2) 36 | return +1; 37 | else 38 | return 0; 39 | 40 | } 41 | 42 | void Integer_fmt(int code, va_list_box *box, 43 | int put(int c, void *cl), void *cl, 44 | unsigned char flags[], int width, int precision) { 45 | char buf[44]; 46 | T integer; 47 | 48 | assert(box && flags); 49 | integer = va_arg(box->ap, T); 50 | assert(integer); 51 | Fmt_putd(buf, Fmt_sfmt(buf, sizeof buf, "%d", *integer), 52 | put, cl, flags, width, precision); 53 | } 54 | -------------------------------------------------------------------------------- /examples/integer.h: -------------------------------------------------------------------------------- 1 | #ifndef INTEGER_INCLUDED 2 | #define INTEGER_INCLUDED 3 | 4 | #define T Integer_T 5 | typedef int *T; 6 | 7 | extern T Integer_new(int n); 8 | extern int Integer_get(T integer); 9 | extern int Integer_put(T integer, int n); 10 | extern int Integer_cmp(T i1, T i2); 11 | extern void Integer_fmt(int code, va_list_box *box, 12 | int put(int c, void *cl), void *cl, 13 | unsigned char flags[], int width, int precision); 14 | 15 | #undef T 16 | #endif 17 | -------------------------------------------------------------------------------- /examples/iref.c: -------------------------------------------------------------------------------- 1 | /* 2 | This version of xref uses the Text, Array, and MP interfaces, 3 | and stores the line numbers in 3-byte MP_Ts in Array_Ts. 4 | It's slow, because it expands Array_Ts one element at a time. 5 | getword picks off the identifiers right-to-left. 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "assert.h" 12 | #include "fmt.h" 13 | #include "mem.h" 14 | #include "mp.h" 15 | #include "table.h" 16 | #include "array.h" 17 | #include "text.h" 18 | 19 | static char rcsid[] = "$Id$"; 20 | 21 | Text_T getword(Text_T *line, Text_T first, Text_T rest) { 22 | int i, j; 23 | 24 | assert(line); 25 | if ((i = Text_rupto(*line, 1, 0, first)) > 0) { 26 | Text_T word = Text_sub(*line, j = Text_rmany(*line, 1, i + 1, rest), i + 1); 27 | *line = Text_sub(*line, 1, j); 28 | return word; 29 | } else 30 | return Text_null; 31 | } 32 | 33 | Text_T first, rest; 34 | 35 | int textcmp(const void *x, const void *y) { 36 | return Text_cmp(*(Text_T *)x, *(Text_T *)y); 37 | } 38 | 39 | int compare(const void *x, const void *y) { 40 | return textcmp(*(Text_T **)x, *(Text_T **)y); 41 | } 42 | 43 | unsigned texthash(const void *x) { 44 | int i; 45 | unsigned h = 0; 46 | const Text_T *t = x; 47 | 48 | for (i = 0; i < t->len; i++) 49 | h = (h<<1) + t->str[i]; 50 | return h; 51 | } 52 | 53 | void print(Table_T files) { 54 | int i; 55 | 56 | void **array = Table_toArray(files, NULL); 57 | qsort(array, Table_length(files), 2*sizeof (*array), compare); 58 | for (i = 0; array[i]; i += 2) { 59 | int j; 60 | Text_T *filename = array[i]; 61 | if (filename->len > 0) 62 | Fmt_print("\t%T:", filename); 63 | for (j = 0; j < Array_length(array[i+1]); j++) 64 | Fmt_print(" %D", Array_get(array[i+1], j), 10); 65 | Fmt_print("\n"); 66 | FREE(filename); 67 | Array_free((Array_T *)&array[i+1]); 68 | } 69 | FREE(array); 70 | Table_free(&files); 71 | } 72 | 73 | Text_T *copy(Text_T t) { 74 | Text_T *p; 75 | 76 | NEW(p); 77 | *p = t; 78 | return p; 79 | } 80 | 81 | void iref(char *name, FILE *fp, Table_T identifiers) { 82 | char buf[512]; 83 | Text_T filename = { 0, "" }; 84 | unsigned char linenum[3]; 85 | 86 | if (name) 87 | filename = Text_put(name); 88 | MP_fromint(linenum, 1); 89 | while (fgets(buf, sizeof buf, fp) != NULL) { 90 | Text_T id, line = Text_put(buf); 91 | while ((id = getword(&line, first, rest)).len > 0) { 92 | Array_T array; 93 | Table_T files; 94 | files = Table_get(identifiers, &id); 95 | if (files == NULL) { 96 | files = Table_new(0, textcmp, texthash); 97 | Table_put(identifiers, copy(id), files); 98 | } 99 | array = Table_get(files, &filename); 100 | if (array == NULL) { 101 | array = Array_new(1, 3); 102 | Table_put(files, copy(filename), array); 103 | Array_put(array, 0, linenum); 104 | } else if (MP_cmp(Array_get(array, Array_length(array)-1), linenum) != 0) { 105 | Array_resize(array, Array_length(array) + 1); 106 | Array_put(array, Array_length(array) - 1, linenum); 107 | } 108 | } 109 | MP_addi(linenum, linenum, 1); 110 | } 111 | } 112 | 113 | int main(int argc, char *argv[]) { 114 | int i; 115 | Table_T identifiers = Table_new(10000, textcmp, texthash); 116 | Text_save_T mark = Text_save(); 117 | 118 | Fmt_register('T', Text_fmt); 119 | Fmt_register('D', MP_fmt); 120 | MP_set(24); 121 | first = Text_cat(Text_cat(Text_ucase, Text_lcase), Text_box("_", 1)); 122 | rest = Text_cat(first, Text_digits); 123 | for (i = 1; i < argc; i++) { 124 | FILE *fp = fopen(argv[i], "r"); 125 | if (fp == NULL) 126 | fprintf(stderr, "%s: can't open '%s' (%s)\n", argv[0], argv[i], strerror(errno)); 127 | else { 128 | iref(argv[i], fp, identifiers); 129 | fclose(fp); 130 | } 131 | } 132 | if (argc == 1) 133 | iref(NULL, stdin, identifiers); 134 | { 135 | int i; 136 | void **array = Table_toArray(identifiers, NULL); 137 | qsort(array, Table_length(identifiers), 2*sizeof (*array), compare); 138 | for (i = 0; array[i]; i += 2) { 139 | Fmt_print("%T", array[i]); 140 | print(array[i+1]); 141 | FREE(array[i]); 142 | } 143 | FREE(array); 144 | Table_free(&identifiers); 145 | } 146 | Text_restore(&mark); 147 | return EXIT_SUCCESS; 148 | } 149 | -------------------------------------------------------------------------------- /examples/kref.c: -------------------------------------------------------------------------------- 1 | /* 2 | This version of xref, which is derived from cref, uses the Str and Seq 3 | interfaces, and it uses Atom_Ts are used for the line numbers. 4 | This version is a possible solution to exercise 11.5. 5 | Also, this version of getword picks off the identifiers from 6 | right to left. 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "assert.h" 13 | #include "atom.h" 14 | #include "fmt.h" 15 | #include "mem.h" 16 | #include "table.h" 17 | #include "seq.h" 18 | #include "str.h" 19 | 20 | static char rcsid[] = "$Id$"; 21 | 22 | int getword(char *line, int *i, char *first, char *rest) { 23 | int j; 24 | 25 | assert(line); 26 | assert(i); 27 | assert(first); 28 | assert(rest); 29 | if ((j = Str_rupto(line, 1, *i, first)) > 0) 30 | j = Str_rmany(line, 1, *i = j + 1, rest); 31 | return j; 32 | } 33 | 34 | char *first, *rest; 35 | 36 | int compare(const void *x, const void *y) { 37 | return Str_cmp(*(char **)x, 1, 0, *(char **)y, 1, 0); 38 | } 39 | 40 | unsigned strhash(const void *x) { 41 | const char *str = x; 42 | unsigned h = 0; 43 | 44 | while (*str) 45 | h = (h<<1) + *str++; 46 | return h; 47 | } 48 | 49 | void print(Table_T files) { 50 | int i; 51 | 52 | void **array = Table_toArray(files, NULL); 53 | qsort(array, Table_length(files), 2*sizeof (*array), compare); 54 | for (i = 0; array[i]; i += 2) { 55 | Seq_T seq = array[i+1]; 56 | char *filename = array[i]; 57 | if (*filename) 58 | Fmt_print("\t%S:", filename, 1, 0); 59 | while (Seq_length(seq) > 0) 60 | Fmt_print(" %S", Seq_remhi(seq), 1, 0); 61 | Fmt_print("\n"); 62 | FREE(filename); 63 | Seq_free(&seq); 64 | } 65 | FREE(array); 66 | Table_free(&files); 67 | } 68 | 69 | void kref(char *name, FILE *fp, Table_T identifiers) { 70 | char buf[512]; 71 | const char *filename = ""; 72 | int linenum; 73 | 74 | if (name) 75 | filename = name; 76 | for (linenum = 1; fgets(buf, sizeof buf, fp) != NULL; linenum++) { 77 | int i, j; 78 | for (i = 0; (j = getword(buf, &i, first, rest)) > 0; i = j) { 79 | char *id = Str_sub(buf, j, i); 80 | const char *ln = Atom_int(linenum); 81 | Seq_T seq; 82 | Table_T files; 83 | files = Table_get(identifiers, id); 84 | if (files == NULL) { 85 | files = Table_new(0, 86 | (int (*)(const void *, const void *))strcmp, strhash); 87 | Table_put(identifiers, id, files); 88 | } else 89 | FREE(id); 90 | seq = Table_get(files, filename); 91 | if (seq == NULL) { 92 | seq = Seq_new(0); 93 | Table_put(files, Str_dup(filename, 1, 0, 1), seq); 94 | Seq_addlo(seq, (void *)ln); 95 | } else if (Seq_get(seq, 0) != ln) 96 | Seq_addlo(seq, (void *)ln); 97 | } 98 | } 99 | } 100 | 101 | int main(int argc, char *argv[]) { 102 | int i; 103 | Table_T identifiers = Table_new(5000, 104 | (int (*)(const void *, const void *))strcmp, strhash); 105 | 106 | Fmt_register('S', Str_fmt); 107 | first = Str_catv("abcdefghijklmnopqrstuvwxyz", 1, 0, 108 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1, 0, "_", 1, 0, NULL); 109 | rest = Str_cat(first, 1, 0, "0123456789", 1, 0); 110 | for (i = 1; i < argc; i++) { 111 | FILE *fp = fopen(argv[i], "r"); 112 | if (fp == NULL) 113 | fprintf(stderr, "%s: can't open '%s' (%s)\n", argv[0], argv[i], strerror(errno)); 114 | else { 115 | kref(argv[i], fp, identifiers); 116 | fclose(fp); 117 | } 118 | } 119 | if (argc == 1) 120 | kref(NULL, stdin, identifiers); 121 | { 122 | int i; 123 | void **array = Table_toArray(identifiers, NULL); 124 | qsort(array, Table_length(identifiers), 2*sizeof (*array), compare); 125 | for (i = 0; array[i]; i += 2) { 126 | Fmt_print("%S", array[i], 1, 0); 127 | print(array[i+1]); 128 | FREE(array[i]); 129 | } 130 | FREE(array); 131 | Table_free(&identifiers); 132 | } 133 | return EXIT_SUCCESS; 134 | } 135 | -------------------------------------------------------------------------------- /examples/mpcalc.c: -------------------------------------------------------------------------------- 1 | static const char *rcsid = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "mem.h" 8 | #include "seq.h" 9 | #include "fmt.h" 10 | #include "mp.h" 11 | Seq_T sp; 12 | int ibase = 10; 13 | int obase = 10; 14 | struct { 15 | const char *fmt; 16 | MP_T (*add)(MP_T, MP_T, MP_T); 17 | MP_T (*sub)(MP_T, MP_T, MP_T); 18 | MP_T (*mul)(MP_T, MP_T, MP_T); 19 | MP_T (*div)(MP_T, MP_T, MP_T); 20 | MP_T (*mod)(MP_T, MP_T, MP_T); 21 | } s = { "%D\n", 22 | MP_add, MP_sub, MP_mul, MP_div, MP_mod }, 23 | u = { "%U\n", 24 | MP_addu, MP_subu, MP_mulu, MP_divu, MP_modu }, 25 | *f = &s; 26 | MP_T pop(void) { 27 | if (Seq_length(sp) > 0) 28 | return Seq_remhi(sp); 29 | else { 30 | Fmt_fprint(stderr, "?stack underflow\n"); 31 | return MP_new(0); 32 | } 33 | } 34 | int main(int argc, char *argv[]) { 35 | int c; 36 | sp = Seq_new(0); 37 | Fmt_register('D', MP_fmt); 38 | Fmt_register('U', MP_fmtu); 39 | while ((c = getchar()) != EOF) { 40 | volatile MP_T x = NULL, y = NULL, z = NULL; 41 | TRY 42 | switch (c) { 43 | default: 44 | if (isprint(c)) 45 | Fmt_fprint(stderr, "?'%c'", c); 46 | else 47 | Fmt_fprint(stderr, "?'\\%03o'", c); 48 | Fmt_fprint(stderr, " is unimplemented\n"); 49 | break; 50 | case ' ': case '\t': case '\n': case '\f': case '\r': 51 | break; 52 | case 'c': while (Seq_length(sp) > 0) { 53 | MP_T x = Seq_remhi(sp); 54 | FREE(x); 55 | } break; 56 | case 'q': while (Seq_length(sp) > 0) { 57 | MP_T x = Seq_remhi(sp); 58 | FREE(x); 59 | } 60 | Seq_free(&sp); 61 | return EXIT_SUCCESS; 62 | case '0': case '1': case '2': case '3': case '4': 63 | case '5': case '6': case '7': case '8': case '9': { 64 | char buf[512]; 65 | z = MP_new(0); 66 | { 67 | int i = 0; 68 | for ( ; strchr(&"zyxwvutsrqponmlkjihgfedcba9876543210"[36-ibase], 69 | tolower(c)); c = getchar(), i++) 70 | if (i < (int)sizeof (buf) - 1) 71 | buf[i] = c; 72 | if (i > (int)sizeof (buf) - 1) { 73 | i = (int)sizeof (buf) - 1; 74 | Fmt_fprint(stderr, 75 | "?integer constant exceeds %d digits\n", i); 76 | } 77 | buf[i] = '\0'; 78 | if (c != EOF) 79 | ungetc(c, stdin); 80 | } 81 | MP_fromstr(z, buf, ibase, NULL); 82 | break; 83 | } 84 | case '+': y = pop(); x = pop(); 85 | z = MP_new(0); (*f->add)(z, x, y); break; 86 | case '-': y = pop(); x = pop(); 87 | z = MP_new(0); (*f->sub)(z, x, y); break; 88 | case '*': y = pop(); x = pop(); 89 | z = MP_new(0); (*f->mul)(z, x, y); break; 90 | case '/': y = pop(); x = pop(); 91 | z = MP_new(0); (*f->div)(z, x, y); break; 92 | case '%': y = pop(); x = pop(); 93 | z = MP_new(0); (*f->mod)(z, x, y); break; 94 | case '&': y = pop(); x = pop(); 95 | z = MP_new(0); MP_and(z, x, y); break; 96 | case '|': y = pop(); x = pop(); 97 | z = MP_new(0); MP_or (z, x, y); break; 98 | case '^': y = pop(); x = pop(); 99 | z = MP_new(0); MP_xor(z, x, y); break; 100 | case '!': z = pop(); MP_not(z, z); break; 101 | case '~': z = pop(); MP_neg(z, z); break; 102 | case 'i': case 'o': { 103 | long n; 104 | x = pop(); 105 | n = MP_toint(x); 106 | if (n < 2 || n > 36) 107 | Fmt_fprint(stderr, "?%d is an illegal base\n",n); 108 | else if (c == 'i') 109 | ibase = n; 110 | else 111 | obase = n; 112 | if (obase == 2 || obase == 8 || obase == 16) 113 | f = &u; 114 | else 115 | f = &s; 116 | break; 117 | } 118 | case 'p': 119 | Fmt_print(f->fmt, z = pop(), obase); 120 | break; 121 | case 'f': { 122 | int n = Seq_length(sp); 123 | while (--n >= 0) 124 | Fmt_print(f->fmt, Seq_get(sp, n), obase); 125 | break; 126 | } 127 | case '<': { long s; 128 | y = pop(); 129 | z = pop(); 130 | s = MP_toint(y); 131 | if (s < 0 || s > INT_MAX) { 132 | Fmt_fprint(stderr, 133 | "?%d is an illegal shift amount\n", s); 134 | break; 135 | }; MP_lshift(z, z, s); break; } 136 | case '>': { long s; 137 | y = pop(); 138 | z = pop(); 139 | s = MP_toint(y); 140 | if (s < 0 || s > INT_MAX) { 141 | Fmt_fprint(stderr, 142 | "?%d is an illegal shift amount\n", s); 143 | break; 144 | }; MP_rshift(z, z, s); break; } 145 | case 'k': { 146 | long n; 147 | x = pop(); 148 | n = MP_toint(x); 149 | if (n < 2 || n > INT_MAX) 150 | Fmt_fprint(stderr, 151 | "?%d is an illegal precision\n", n); 152 | else if (Seq_length(sp) > 0) 153 | Fmt_fprint(stderr, "?nonempty stack\n"); 154 | else 155 | MP_set(n); 156 | break; 157 | } 158 | case 'd': { 159 | MP_T x = pop(); 160 | z = MP_new(0); 161 | Seq_addhi(sp, x); 162 | MP_addui(z, x, 0); 163 | break; 164 | } 165 | } 166 | EXCEPT(MP_Overflow) 167 | Fmt_fprint(stderr, "?overflow\n"); 168 | EXCEPT(MP_Dividebyzero) 169 | Fmt_fprint(stderr, "?divide by 0\n"); 170 | END_TRY; 171 | if (z) 172 | Seq_addhi(sp, z); 173 | FREE(x); 174 | FREE(y); 175 | } 176 | while (Seq_length(sp) > 0) { 177 | MP_T x = Seq_remhi(sp); 178 | FREE(x); 179 | } 180 | Seq_free(&sp); 181 | return EXIT_SUCCESS; 182 | } 183 | -------------------------------------------------------------------------------- /examples/sieve.c: -------------------------------------------------------------------------------- 1 | static const char *rcsid = "$Id$" "\n$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "fmt.h" 6 | #include "thread.h" 7 | #include "chan.h" 8 | struct args { 9 | Chan_T c; 10 | int n, last; 11 | }; 12 | int source(void *cl) { 13 | struct args *p = cl; 14 | int i = 2; 15 | if (Chan_send(p->c, &i, sizeof i)) 16 | for (i = 3; Chan_send(p->c, &i, sizeof i); ) 17 | i += 2; 18 | return EXIT_SUCCESS; 19 | } 20 | void filter(int primes[], Chan_T input, Chan_T output) { 21 | int j, x; 22 | for (;;) { 23 | Chan_receive(input, &x, sizeof x); 24 | for (j = 0; primes[j] != 0 && x%primes[j] != 0; j++) 25 | ; 26 | if (primes[j] == 0) 27 | if (Chan_send(output, &x, sizeof x) == 0) 28 | break; 29 | } 30 | Chan_receive(input, &x, 0); 31 | } 32 | int sink(void *cl) { 33 | struct args *p = cl; 34 | Chan_T input = p->c; 35 | int i = 0, j, x, primes[256]; 36 | primes[0] = 0; 37 | for (;;) { 38 | Chan_receive(input, &x, sizeof x); 39 | for (j = 0; primes[j] != 0 && x%primes[j] != 0; j++) 40 | ; 41 | if (primes[j] == 0) { 42 | if (x > p->last) 43 | break; 44 | Fmt_print(" %d", x); 45 | primes[i++] = x; 46 | primes[i] = 0; 47 | if (i == p->n) 48 | { 49 | p->c = Chan_new(); 50 | Thread_new(sink, p, sizeof *p, NULL); 51 | filter(primes, input, p->c); 52 | return EXIT_SUCCESS; 53 | } 54 | } 55 | } 56 | Fmt_print("\n"); 57 | Chan_receive(input, &x, 0); 58 | return EXIT_SUCCESS; 59 | } 60 | int main(int argc, char *argv[]) { 61 | struct args args; 62 | Thread_init(1, NULL); 63 | args.c = Chan_new(); 64 | Thread_new(source, &args, sizeof args, NULL); 65 | args.n = argc > 2 ? atoi(argv[2]) : 5; 66 | args.last = argc > 1 ? atoi(argv[1]) : 1000; 67 | Thread_new(sink, &args, sizeof args, NULL); 68 | Thread_exit(EXIT_SUCCESS); 69 | return EXIT_SUCCESS; 70 | } 71 | -------------------------------------------------------------------------------- /examples/sort.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$" "\n$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include "assert.h" 6 | #include "fmt.h" 7 | #include "thread.h" 8 | #include "mem.h" 9 | struct args { 10 | int *a; 11 | int lb, ub; 12 | }; 13 | int cutoff = 10000; 14 | #include 15 | #define Fmt_print outs 16 | 17 | static void outs(const char *fmt, ...) { 18 | char *buf; 19 | va_list_box box; 20 | 21 | va_start(box.ap, fmt); 22 | buf = Fmt_vstring(fmt, &box); 23 | va_end(box.ap); 24 | printf("%s", buf); 25 | FREE(buf); 26 | } 27 | 28 | int partition(int a[], int i, int j) { 29 | int v, k, t; 30 | j++; 31 | k = i; 32 | v = a[k]; 33 | while (i < j) { 34 | i++; while (a[i] < v && i < j) i++; 35 | j--; while (a[j] > v ) j--; 36 | if (i < j) { t = a[i]; a[i] = a[j]; a[j] = t; } 37 | } 38 | t = a[k]; a[k] = a[j]; a[j] = t; 39 | return j; 40 | } 41 | int quick(void *cl) { 42 | struct args *p = cl; 43 | int lb = p->lb, ub = p->ub; 44 | if (lb < ub) { 45 | int k = partition(p->a, lb, ub); 46 | p->lb = lb; 47 | p->ub = k - 1; 48 | if (k - lb > cutoff) { 49 | Thread_T t; 50 | t = Thread_new(quick, p, sizeof *p, NULL); 51 | Fmt_print("thread %p sorted %d..%d\n", t, lb, k - 1); 52 | } else 53 | quick(p); 54 | p->lb = k + 1; 55 | p->ub = ub; 56 | if (ub - k > cutoff) { 57 | Thread_T t; 58 | t = Thread_new(quick, p, sizeof *p, NULL); 59 | Fmt_print("thread %p sorted %d..%d\n", t, k + 1, ub); 60 | } else 61 | quick(p); 62 | } 63 | return EXIT_SUCCESS; 64 | } 65 | void sort(int *x, int n, int argc, char *argv[]) { 66 | struct args args; 67 | if (argc >= 3) 68 | cutoff = atoi(argv[2]); 69 | args.a = x; 70 | args.lb = 0; 71 | args.ub = n - 1; 72 | quick(&args); 73 | Thread_join(NULL); 74 | } 75 | main(int argc, char *argv[]) { 76 | int i, n = 100000, *x, preempt; 77 | preempt = Thread_init(1, NULL); 78 | assert(preempt == 1); 79 | if (argc >= 2) 80 | n = atoi(argv[1]); 81 | x = CALLOC(n, sizeof (int)); 82 | srand(time(NULL)); 83 | for (i = 0; i < n; i++) 84 | x[i] = rand(); 85 | sort(x, n, argc, argv); 86 | for (i = 1; i < n; i++) 87 | if (x[i] < x[i-1]) 88 | break; 89 | assert(i == n); 90 | Thread_exit(EXIT_SUCCESS); 91 | return EXIT_SUCCESS; 92 | } 93 | -------------------------------------------------------------------------------- /examples/spin.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "fmt.h" 6 | #include "thread.h" 7 | #include "sem.h" 8 | #define NBUMP 30000 9 | struct args { 10 | Sem_T *mutex; 11 | int *ip; 12 | }; 13 | int unsafe(void *cl) { 14 | int i, *ip = cl; 15 | for (i = 0; i < NBUMP; i++) 16 | *ip = *ip + 1; 17 | return EXIT_SUCCESS; 18 | } 19 | int safe(void *cl) { 20 | struct args *p = cl; 21 | int i; 22 | for (i = 0; i < NBUMP; i++) 23 | LOCK(*p->mutex) 24 | *p->ip = *p->ip + 1; 25 | END_LOCK; 26 | return EXIT_SUCCESS; 27 | } 28 | int n; 29 | int main(int argc, char *argv[]) { 30 | int m = 5, preempt; 31 | preempt = Thread_init(1, NULL); 32 | assert(preempt == 1); 33 | if (argc >= 2) 34 | m = atoi(argv[1]); 35 | n = 0; 36 | { 37 | int i; 38 | for (i = 0; i < m; i++) 39 | Thread_new(unsafe, &n, 0, NULL); 40 | Thread_join(NULL); 41 | } 42 | Fmt_print("%d == %d\n", n, NBUMP*m); 43 | n = 0; 44 | { 45 | int i; 46 | struct args args; 47 | Sem_T mutex; 48 | Sem_init(&mutex, 1); 49 | args.mutex = &mutex; 50 | args.ip = &n; 51 | for (i = 0; i < m; i++) 52 | Thread_new(safe, &args, sizeof args, NULL); 53 | Thread_join(NULL); 54 | } 55 | Fmt_print("%d == %d\n", n, NBUMP*m); 56 | Thread_exit(EXIT_SUCCESS); 57 | return EXIT_SUCCESS; 58 | } 59 | -------------------------------------------------------------------------------- /examples/wf.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "atom.h" 7 | #include "table.h" 8 | #include "mem.h" 9 | #include "getword.h" 10 | #include 11 | void wf(char *, FILE *); 12 | int first(int c); 13 | int rest (int c); 14 | int compare(const void *x, const void *y); 15 | void vfree(const void *, void **, void *); 16 | int main(int argc, char *argv[]) { 17 | int i; 18 | for (i = 1; i < argc; i++) { 19 | FILE *fp = fopen(argv[i], "r"); 20 | if (fp == NULL) { 21 | fprintf(stderr, "%s: can't open '%s' (%s)\n", 22 | argv[0], argv[i], strerror(errno)); 23 | return EXIT_FAILURE; 24 | } else { 25 | wf(argv[i], fp); 26 | fclose(fp); 27 | } 28 | } 29 | if (argc == 1) wf(NULL, stdin); 30 | return EXIT_SUCCESS; 31 | } 32 | void wf(char *name, FILE *fp) { 33 | Table_T table = Table_new(0, NULL, NULL); 34 | char buf[128]; 35 | while (getword(fp, buf, sizeof buf, first, rest)) { 36 | const char *word; 37 | int i, *count; 38 | for (i = 0; buf[i] != '\0'; i++) 39 | buf[i] = tolower(buf[i]); 40 | word = Atom_string(buf); 41 | count = Table_get(table, word); 42 | if (count) 43 | (*count)++; 44 | else { 45 | NEW(count); 46 | *count = 1; 47 | Table_put(table, word, count); 48 | } 49 | } 50 | if (name) 51 | printf("%s:\n", name); 52 | { int i; 53 | void **array = Table_toArray(table, NULL); 54 | qsort(array, Table_length(table), 2*sizeof (*array), 55 | compare); 56 | for (i = 0; array[i]; i += 2) 57 | printf("%d\t%s\n", *(int *)array[i+1], 58 | (char *)array[i]); 59 | FREE(array); } 60 | Table_map(table, vfree, NULL); 61 | Table_free(&table); 62 | } 63 | int first(int c) { 64 | return isalpha(c); 65 | } 66 | int rest(int c) { 67 | return isalpha(c) || c == '_'; 68 | } 69 | int compare(const void *x, const void *y) { 70 | return strcmp(*(char **)x, *(char **)y); 71 | } 72 | void vfree(const void *key, void **count, void *cl) { 73 | FREE(*count); 74 | } 75 | -------------------------------------------------------------------------------- /examples/words.c: -------------------------------------------------------------------------------- 1 | /* 2 | This version of ids uses Text and Ring, 3 | and reads the identifiers from right to left. 4 | This version is a circuitous solution to Exercise 16.1. 5 | */ 6 | #include 7 | #include 8 | #include "fmt.h" 9 | #include "ring.h" 10 | #include "text.h" 11 | #include "mem.h" 12 | 13 | int main(int argc, char *argv[]) { 14 | char buf[512]; 15 | Text_save_T save = Text_save(); 16 | Ring_T ring = Ring_new(); 17 | Text_T first = Text_cat(Text_cat(Text_ucase, Text_lcase), Text_box("_", 1)); 18 | Text_T rest = Text_cat(first, Text_digits); 19 | 20 | Fmt_register('T', Text_fmt); 21 | while (fgets(buf, sizeof buf, stdin) != NULL) { 22 | Text_T line = Text_put(buf), *id; 23 | int j = 0; 24 | while ((j = Text_rupto(line, 1, j, first)) > 0) { 25 | int i = Text_rmany(line, 1, j + 1, rest); 26 | NEW(id); 27 | *id = Text_sub(line, i, j + 1); 28 | Ring_addlo(ring, id); 29 | j = i; 30 | } 31 | while (Ring_length(ring) > 0) { 32 | id = Ring_remlo(ring); 33 | Fmt_print("%T\n", id); 34 | FREE(id); 35 | } 36 | 37 | } 38 | Ring_free(&ring); 39 | Text_restore(&save); 40 | return EXIT_SUCCESS; 41 | } 42 | -------------------------------------------------------------------------------- /examples/xref.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include "table.h" 6 | #include 7 | #include "atom.h" 8 | #include "set.h" 9 | #include "mem.h" 10 | #include "getword.h" 11 | #include 12 | int compare(const void *x, const void *y); 13 | void print(Table_T); 14 | int cmpint(const void *x, const void *y); 15 | void xref(const char *, FILE *, Table_T); 16 | int first(int c); 17 | int rest (int c); 18 | int intcmp (const void *x, const void *y); 19 | unsigned inthash(const void *x); 20 | int linenum; 21 | int main(int argc, char *argv[]) { 22 | int i; 23 | Table_T identifiers = Table_new(0, NULL, NULL); 24 | for (i = 1; i < argc; i++) { 25 | FILE *fp = fopen(argv[i], "r"); 26 | if (fp == NULL) { 27 | fprintf(stderr, "%s: can't open '%s' (%s)\n", 28 | argv[0], argv[i], strerror(errno)); 29 | return EXIT_FAILURE; 30 | } else { 31 | xref(argv[i], fp, identifiers); 32 | fclose(fp); 33 | } 34 | } 35 | if (argc == 1) xref(NULL, stdin, identifiers); 36 | { 37 | int i; 38 | void **array = Table_toArray(identifiers, NULL); 39 | qsort(array, Table_length(identifiers), 40 | 2*sizeof (*array), compare); 41 | for (i = 0; array[i]; i += 2) { 42 | printf("%s", (char *)array[i]); 43 | print(array[i+1]); 44 | } 45 | FREE(array); 46 | } 47 | return EXIT_SUCCESS; 48 | } 49 | int compare(const void *x, const void *y) { 50 | return strcmp(*(char **)x, *(char **)y); 51 | } 52 | void print(Table_T files) { 53 | int i; 54 | void **array = Table_toArray(files, NULL); 55 | qsort(array, Table_length(files), 2*sizeof (*array), 56 | compare); 57 | for (i = 0; array[i]; i += 2) { 58 | if (*(char *)array[i] != '\0') 59 | printf("\t%s:", (char *)array[i]); 60 | { 61 | int j; 62 | void **lines = Set_toArray(array[i+1], NULL); 63 | qsort(lines, Set_length(array[i+1]), sizeof (*lines), 64 | cmpint); 65 | for (j = 0; lines[j]; j++) 66 | printf(" %d", *(int *)lines[j]); 67 | FREE(lines); 68 | } 69 | printf("\n"); 70 | } 71 | FREE(array); 72 | } 73 | int cmpint(const void *x, const void *y) { 74 | if (**(int **)x < **(int **)y) 75 | return -1; 76 | else if (**(int **)x > **(int **)y) 77 | return +1; 78 | else 79 | return 0; 80 | } 81 | void xref(const char *name, FILE *fp, 82 | Table_T identifiers){ 83 | char buf[128]; 84 | if (name == NULL) 85 | name = ""; 86 | name = Atom_string(name); 87 | linenum = 1; 88 | while (getword(fp, buf, sizeof buf, first, rest)) { 89 | Set_T set; 90 | Table_T files; 91 | const char *id = Atom_string(buf); 92 | files = Table_get(identifiers, id); 93 | if (files == NULL) { 94 | files = Table_new(0, NULL, NULL); 95 | Table_put(identifiers, id, files); 96 | } 97 | set = Table_get(files, name); 98 | if (set == NULL) { 99 | set = Set_new(0, intcmp, inthash); 100 | Table_put(files, name, set); 101 | } 102 | { 103 | int *p = &linenum; 104 | if (!Set_member(set, p)) { 105 | NEW(p); 106 | *p = linenum; 107 | Set_put(set, p); 108 | } 109 | } 110 | } 111 | } 112 | int first(int c) { 113 | if (c == '\n') 114 | linenum++; 115 | return isalpha(c) || c == '_'; 116 | } 117 | int rest(int c) { 118 | return isalpha(c) || c == '_' || isdigit(c); 119 | } 120 | int intcmp(const void *x, const void *y) { 121 | return cmpint(&x, &y); 122 | } 123 | unsigned inthash(const void *x) { 124 | return *(int *)x; 125 | } 126 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | pkginclude_HEADERS = ap.h \ 2 | arena.h \ 3 | arith.h \ 4 | array.h \ 5 | arrayrep.h \ 6 | assert.h \ 7 | atom.h \ 8 | bit.h \ 9 | chan.h \ 10 | except.h \ 11 | fmt.h \ 12 | list.h \ 13 | mem.h \ 14 | mp.h \ 15 | ring.h \ 16 | sem.h \ 17 | seq.h \ 18 | set.h \ 19 | stack.h \ 20 | str.h \ 21 | table.h \ 22 | text.h \ 23 | thread.h \ 24 | xp.h 25 | -------------------------------------------------------------------------------- /include/ap.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef AP_INCLUDED 3 | #define AP_INCLUDED 4 | #include 5 | #include "fmt.h" 6 | #define T AP_T 7 | typedef struct T *T; 8 | extern T AP_new (long int n); 9 | extern T AP_fromstr(const char *str, int base, 10 | char **end); 11 | extern long int AP_toint(T x); 12 | extern char *AP_tostr(char *str, int size, 13 | int base, T x); 14 | extern void AP_fmt(int code, va_list_box *box, 15 | int put(int c, void *cl), void *cl, 16 | unsigned char flags[], int width, int precision); 17 | extern void AP_free(T *z); 18 | extern T AP_neg(T x); 19 | extern T AP_add(T x, T y); 20 | extern T AP_sub(T x, T y); 21 | extern T AP_mul(T x, T y); 22 | extern T AP_div(T x, T y); 23 | extern T AP_mod(T x, T y); 24 | extern T AP_pow(T x, T y, T p); 25 | extern T AP_addi(T x, long int y); 26 | extern T AP_subi(T x, long int y); 27 | extern T AP_muli(T x, long int y); 28 | extern T AP_divi(T x, long int y); 29 | extern long AP_modi(T x, long int y); 30 | extern T AP_lshift(T x, int s); 31 | extern T AP_rshift(T x, int s); 32 | extern int AP_cmp (T x, T y); 33 | extern int AP_cmpi(T x, long int y); 34 | #undef T 35 | #endif 36 | -------------------------------------------------------------------------------- /include/arena.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef ARENA_INCLUDED 3 | #define ARENA_INCLUDED 4 | #include "except.h" 5 | #define T Arena_T 6 | typedef struct T *T; 7 | extern const Except_T Arena_NewFailed; 8 | extern const Except_T Arena_Failed; 9 | extern T Arena_new (void); 10 | extern void Arena_dispose(T *ap); 11 | extern void *Arena_alloc (T arena, long nbytes, 12 | const char *file, int line); 13 | extern void *Arena_calloc(T arena, long count, 14 | long nbytes, const char *file, int line); 15 | extern void Arena_free (T arena); 16 | #undef T 17 | #endif 18 | -------------------------------------------------------------------------------- /include/arith.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | extern int Arith_max(int x, int y); 3 | extern int Arith_min(int x, int y); 4 | extern int Arith_div(int x, int y); 5 | extern int Arith_mod(int x, int y); 6 | extern int Arith_ceiling(int x, int y); 7 | extern int Arith_floor (int x, int y); 8 | -------------------------------------------------------------------------------- /include/array.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef ARRAY_INCLUDED 3 | #define ARRAY_INCLUDED 4 | #define T Array_T 5 | typedef struct T *T; 6 | extern T Array_new (int length, int size); 7 | extern void Array_free(T *array); 8 | extern int Array_length(T array); 9 | extern int Array_size (T array); 10 | extern void *Array_get(T array, int i); 11 | extern void *Array_put(T array, int i, void *elem); 12 | extern void Array_resize(T array, int length); 13 | extern T Array_copy (T array, int length); 14 | #undef T 15 | #endif 16 | -------------------------------------------------------------------------------- /include/arrayrep.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef ARRAYREP_INCLUDED 3 | #define ARRAYREP_INCLUDED 4 | #define T Array_T 5 | struct T { 6 | int length; 7 | int size; 8 | char *array; 9 | }; 10 | extern void ArrayRep_init(T array, int length, 11 | int size, void *ary); 12 | #undef T 13 | #endif 14 | -------------------------------------------------------------------------------- /include/assert.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #undef assert 3 | #ifdef NDEBUG 4 | #define assert(e) ((void)0) 5 | #else 6 | #include "except.h" 7 | extern void assert(int e); 8 | #define assert(e) ((void)((e)||(RAISE(Assert_Failed),0))) 9 | #endif 10 | -------------------------------------------------------------------------------- /include/atom.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef ATOM_INCLUDED 3 | #define ATOM_INCLUDED 4 | extern int Atom_length(const char *str); 5 | extern const char *Atom_new (const char *str, int len); 6 | extern const char *Atom_string(const char *str); 7 | extern const char *Atom_int (long n); 8 | #endif 9 | -------------------------------------------------------------------------------- /include/bit.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef BIT_INCLUDED 3 | #define BIT_INCLUDED 4 | #define T Bit_T 5 | typedef struct T *T; 6 | extern T Bit_new (int length); 7 | extern int Bit_length(T set); 8 | extern int Bit_count (T set); 9 | extern void Bit_free(T *set); 10 | extern int Bit_get(T set, int n); 11 | extern int Bit_put(T set, int n, int bit); 12 | extern void Bit_clear(T set, int lo, int hi); 13 | extern void Bit_set (T set, int lo, int hi); 14 | extern void Bit_not (T set, int lo, int hi); 15 | extern int Bit_lt (T s, T t); 16 | extern int Bit_eq (T s, T t); 17 | extern int Bit_leq(T s, T t); 18 | extern void Bit_map(T set, 19 | void apply(int n, int bit, void *cl), void *cl); 20 | extern T Bit_union(T s, T t); 21 | extern T Bit_inter(T s, T t); 22 | extern T Bit_minus(T s, T t); 23 | extern T Bit_diff (T s, T t); 24 | #undef T 25 | #endif 26 | -------------------------------------------------------------------------------- /include/chan.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef CHAN_INCLUDED 3 | #define CHAN_INCLUDED 4 | #define T Chan_T 5 | typedef struct T *T; 6 | extern T Chan_new (void); 7 | extern int Chan_send (T c, const void *ptr, int size); 8 | extern int Chan_receive(T c, void *ptr, int size); 9 | #undef T 10 | #endif 11 | -------------------------------------------------------------------------------- /include/except.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef EXCEPT_INCLUDED 3 | #define EXCEPT_INCLUDED 4 | #include 5 | #define T Except_T 6 | typedef struct T { 7 | const char *reason; 8 | } T; 9 | typedef struct Except_Frame Except_Frame; 10 | struct Except_Frame { 11 | Except_Frame *prev; 12 | jmp_buf env; 13 | const char *file; 14 | int line; 15 | const T *exception; 16 | }; 17 | enum { Except_entered=0, Except_raised, 18 | Except_handled, Except_finalized }; 19 | extern Except_Frame *Except_stack; 20 | extern const Except_T Assert_Failed; 21 | void Except_raise(const T *e, const char *file,int line); 22 | #ifdef WIN32 23 | #include 24 | 25 | extern int Except_index; 26 | extern void Except_init(void); 27 | extern void Except_push(Except_Frame *fp); 28 | extern void Except_pop(void); 29 | #endif 30 | #ifdef WIN32 31 | /* $Id$ */ 32 | #define RAISE(e) Except_raise(&(e), __FILE__, __LINE__) 33 | #define RERAISE Except_raise(Except_frame.exception, \ 34 | Except_frame.file, Except_frame.line) 35 | #define RETURN switch (Except_pop(),0) default: return 36 | #define TRY do { \ 37 | volatile int Except_flag; \ 38 | Except_Frame Except_frame; \ 39 | if (Except_index == -1) \ 40 | Except_init(); \ 41 | Except_push(&Except_frame); \ 42 | Except_flag = setjmp(Except_frame.env); \ 43 | if (Except_flag == Except_entered) { 44 | #define EXCEPT(e) \ 45 | if (Except_flag == Except_entered) Except_pop(); \ 46 | } else if (Except_frame.exception == &(e)) { \ 47 | Except_flag = Except_handled; 48 | #define ELSE \ 49 | if (Except_flag == Except_entered) Except_pop(); \ 50 | } else { \ 51 | Except_flag = Except_handled; 52 | #define FINALLY \ 53 | if (Except_flag == Except_entered) Except_pop(); \ 54 | } { \ 55 | if (Except_flag == Except_entered) \ 56 | Except_flag = Except_finalized; 57 | #define END_TRY \ 58 | if (Except_flag == Except_entered) Except_pop(); \ 59 | } if (Except_flag == Except_raised) RERAISE; \ 60 | } while (0) 61 | #else 62 | #define RAISE(e) Except_raise(&(e), __FILE__, __LINE__) 63 | #define RERAISE Except_raise(Except_frame.exception, \ 64 | Except_frame.file, Except_frame.line) 65 | #define RETURN switch (Except_stack = Except_stack->prev,0) default: return 66 | #define TRY do { \ 67 | volatile int Except_flag; \ 68 | Except_Frame Except_frame; \ 69 | Except_frame.prev = Except_stack; \ 70 | Except_stack = &Except_frame; \ 71 | Except_flag = setjmp(Except_frame.env); \ 72 | if (Except_flag == Except_entered) { 73 | #define EXCEPT(e) \ 74 | if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \ 75 | } else if (Except_frame.exception == &(e)) { \ 76 | Except_flag = Except_handled; 77 | #define ELSE \ 78 | if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \ 79 | } else { \ 80 | Except_flag = Except_handled; 81 | #define FINALLY \ 82 | if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \ 83 | } { \ 84 | if (Except_flag == Except_entered) \ 85 | Except_flag = Except_finalized; 86 | #define END_TRY \ 87 | if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \ 88 | } if (Except_flag == Except_raised) RERAISE; \ 89 | } while (0) 90 | #endif 91 | #undef T 92 | #endif 93 | -------------------------------------------------------------------------------- /include/fmt.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef FMT_INCLUDED 3 | #define FMT_INCLUDED 4 | #include 5 | #include 6 | #include "except.h" 7 | typedef struct va_list_box { 8 | va_list ap; 9 | } va_list_box; 10 | #define T Fmt_T 11 | typedef void (*T)(int code, va_list_box *box, 12 | int put(int c, void *cl), void *cl, 13 | unsigned char flags[256], int width, int precision); 14 | extern char *Fmt_flags; 15 | extern const Except_T Fmt_Overflow; 16 | extern void Fmt_fmt (int put(int c, void *cl), void *cl, 17 | const char *fmt, ...); 18 | extern void Fmt_vfmt(int put(int c, void *cl), void *cl, 19 | const char *fmt, va_list_box *box); 20 | extern void Fmt_print (const char *fmt, ...); 21 | extern void Fmt_fprint(FILE *stream, 22 | const char *fmt, ...); 23 | extern int Fmt_sfmt (char *buf, int size, 24 | const char *fmt, ...); 25 | extern int Fmt_vsfmt(char *buf, int size, 26 | const char *fmt, va_list_box *box); 27 | extern char *Fmt_string (const char *fmt, ...); 28 | extern char *Fmt_vstring(const char *fmt, va_list_box *box); 29 | extern T Fmt_register(int code, T cvt); 30 | extern void Fmt_putd(const char *str, int len, 31 | int put(int c, void *cl), void *cl, 32 | unsigned char flags[256], int width, int precision); 33 | extern void Fmt_puts(const char *str, int len, 34 | int put(int c, void *cl), void *cl, 35 | unsigned char flags[256], int width, int precision); 36 | #undef T 37 | #endif 38 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef LIST_INCLUDED 3 | #define LIST_INCLUDED 4 | #define T List_T 5 | typedef struct T *T; 6 | struct T { 7 | T rest; 8 | void *first; 9 | }; 10 | extern T List_append (T list, T tail); 11 | extern T List_copy (T list); 12 | extern T List_list (void *x, ...); 13 | extern T List_pop (T list, void **x); 14 | extern T List_push (T list, void *x); 15 | extern T List_reverse(T list); 16 | extern int List_length (T list); 17 | extern void List_free (T *list); 18 | extern void List_map (T list, 19 | void apply(void **x, void *cl), void *cl); 20 | extern void **List_toArray(T list, void *end); 21 | #undef T 22 | #endif 23 | -------------------------------------------------------------------------------- /include/mem.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef MEM_INCLUDED 3 | #define MEM_INCLUDED 4 | #include "except.h" 5 | extern const Except_T Mem_Failed; 6 | extern void *Mem_alloc (long nbytes, 7 | const char *file, int line); 8 | extern void *Mem_calloc(long count, long nbytes, 9 | const char *file, int line); 10 | extern void Mem_free(void *ptr, 11 | const char *file, int line); 12 | extern void *Mem_resize(void *ptr, long nbytes, 13 | const char *file, int line); 14 | #define ALLOC(nbytes) \ 15 | Mem_alloc((nbytes), __FILE__, __LINE__) 16 | #define CALLOC(count, nbytes) \ 17 | Mem_calloc((count), (nbytes), __FILE__, __LINE__) 18 | #define NEW(p) ((p) = ALLOC((long)sizeof *(p))) 19 | #define NEW0(p) ((p) = CALLOC(1, (long)sizeof *(p))) 20 | #define FREE(ptr) ((void)(Mem_free((ptr), \ 21 | __FILE__, __LINE__), (ptr) = 0)) 22 | #define RESIZE(ptr, nbytes) ((ptr) = Mem_resize((ptr), \ 23 | (nbytes), __FILE__, __LINE__)) 24 | #endif 25 | -------------------------------------------------------------------------------- /include/mp.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef MP_INCLUDED 3 | #define MP_INCLUDED 4 | #include 5 | #include 6 | #include "except.h" 7 | #include "fmt.h" 8 | #define T MP_T 9 | typedef unsigned char *T; 10 | extern const Except_T MP_Overflow; 11 | extern const Except_T MP_Dividebyzero; 12 | extern int MP_set(int n); 13 | extern T MP_new(unsigned long u); 14 | extern T MP_fromint (T z, long v); 15 | extern T MP_fromintu(T z, unsigned long u); 16 | extern unsigned long MP_tointu(T x); 17 | extern long MP_toint (T x); 18 | extern T MP_cvt (int m, T z, T x); 19 | extern T MP_cvtu(int m, T z, T x); 20 | extern T MP_add (T z, T x, T y); 21 | extern T MP_sub (T z, T x, T y); 22 | extern T MP_mul (T z, T x, T y); 23 | extern T MP_div (T z, T x, T y); 24 | extern T MP_mod (T z, T x, T y); 25 | extern T MP_neg (T z, T x); 26 | extern T MP_addu(T z, T x, T y); 27 | extern T MP_subu(T z, T x, T y); 28 | extern T MP_mulu(T z, T x, T y); 29 | extern T MP_divu(T z, T x, T y); 30 | extern T MP_modu(T z, T x, T y); 31 | extern T MP_mul2u(T z, T x, T y); 32 | extern T MP_mul2 (T z, T x, T y); 33 | extern T MP_addi (T z, T x, long y); 34 | extern T MP_subi (T z, T x, long y); 35 | extern T MP_muli (T z, T x, long y); 36 | extern T MP_divi (T z, T x, long y); 37 | extern T MP_addui(T z, T x, unsigned long y); 38 | extern T MP_subui(T z, T x, unsigned long y); 39 | extern T MP_mului(T z, T x, unsigned long y); 40 | extern T MP_divui(T z, T x, unsigned long y); 41 | extern long MP_modi (T x, long y); 42 | extern unsigned long MP_modui(T x, unsigned long y); 43 | extern int MP_cmp (T x, T y); 44 | extern int MP_cmpi (T x, long y); 45 | extern int MP_cmpu (T x, T y); 46 | extern int MP_cmpui(T x, unsigned long y); 47 | extern T MP_and (T z, T x, T y); 48 | extern T MP_or (T z, T x, T y); 49 | extern T MP_xor (T z, T x, T y); 50 | extern T MP_not (T z, T x); 51 | extern T MP_andi(T z, T x, unsigned long y); 52 | extern T MP_ori (T z, T x, unsigned long y); 53 | extern T MP_xori(T z, T x, unsigned long y); 54 | extern T MP_lshift(T z, T x, int s); 55 | extern T MP_rshift(T z, T x, int s); 56 | extern T MP_ashift(T z, T x, int s); 57 | extern T MP_fromstr(T z, const char *str, 58 | int base, char **end); 59 | extern char *MP_tostr (char *str, int size, 60 | int base, T x); 61 | extern void MP_fmt (int code, va_list_box *box, 62 | int put(int c, void *cl), void *cl, 63 | unsigned char flags[], int width, int precision); 64 | extern void MP_fmtu (int code, va_list_box *box, 65 | int put(int c, void *cl), void *cl, 66 | unsigned char flags[], int width, int precision); 67 | #undef T 68 | #endif 69 | -------------------------------------------------------------------------------- /include/ring.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef RING_INCLUDED 3 | #define RING_INCLUDED 4 | #define T Ring_T 5 | typedef struct T *T; 6 | extern T Ring_new (void); 7 | extern T Ring_ring(void *x, ...); 8 | extern void Ring_free (T *ring); 9 | extern int Ring_length(T ring); 10 | extern void *Ring_get(T ring, int i); 11 | extern void *Ring_put(T ring, int i, void *x); 12 | extern void *Ring_add(T ring, int pos, void *x); 13 | extern void *Ring_addlo(T ring, void *x); 14 | extern void *Ring_addhi(T ring, void *x); 15 | extern void *Ring_remove(T ring, int i); 16 | extern void *Ring_remlo(T ring); 17 | extern void *Ring_remhi(T ring); 18 | extern void Ring_rotate(T ring, int n); 19 | #undef T 20 | #endif 21 | -------------------------------------------------------------------------------- /include/sem.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef SEM_INCLUDED 3 | #define SEM_INCLUDED 4 | #define T Sem_T 5 | typedef struct T { 6 | int count; 7 | void *queue; 8 | } T; 9 | #define LOCK(mutex) do { Sem_T *_yymutex = &(mutex); \ 10 | Sem_wait(_yymutex); 11 | #define END_LOCK Sem_signal(_yymutex); } while (0) 12 | extern void Sem_init (T *s, int count); 13 | extern T *Sem_new (int count); 14 | extern void Sem_wait (T *s); 15 | extern void Sem_signal(T *s); 16 | #undef T 17 | #endif 18 | -------------------------------------------------------------------------------- /include/seq.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef SEQ_INCLUDED 3 | #define SEQ_INCLUDED 4 | #define T Seq_T 5 | typedef struct T *T; 6 | extern T Seq_new(int hint); 7 | extern T Seq_seq(void *x, ...); 8 | extern void Seq_free(T *seq); 9 | extern int Seq_length(T seq); 10 | extern void *Seq_get(T seq, int i); 11 | extern void *Seq_put(T seq, int i, void *x); 12 | extern void *Seq_addlo(T seq, void *x); 13 | extern void *Seq_addhi(T seq, void *x); 14 | extern void *Seq_remlo(T seq); 15 | extern void *Seq_remhi(T seq); 16 | #undef T 17 | #endif 18 | -------------------------------------------------------------------------------- /include/set.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef SET_INCLUDED 3 | #define SET_INCLUDED 4 | #define T Set_T 5 | typedef struct T *T; 6 | extern T Set_new (int hint, 7 | int cmp(const void *x, const void *y), 8 | unsigned hash(const void *x)); 9 | extern void Set_free(T *set); 10 | extern int Set_length(T set); 11 | extern int Set_member(T set, const void *member); 12 | extern void Set_put (T set, const void *member); 13 | extern void *Set_remove(T set, const void *member); 14 | extern void Set_map (T set, 15 | void apply(const void *member, void *cl), void *cl); 16 | extern void **Set_toArray(T set, void *end); 17 | extern T Set_union(T s, T t); 18 | extern T Set_inter(T s, T t); 19 | extern T Set_minus(T s, T t); 20 | extern T Set_diff (T s, T t); 21 | #undef T 22 | #endif 23 | -------------------------------------------------------------------------------- /include/stack.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef STACK_INCLUDED 3 | #define STACK_INCLUDED 4 | #define T Stack_T 5 | typedef struct T *T; 6 | extern T Stack_new (void); 7 | extern int Stack_empty(T stk); 8 | extern void Stack_push (T stk, void *x); 9 | extern void *Stack_pop (T stk); 10 | extern void Stack_free (T *stk); 11 | #undef T 12 | #endif 13 | -------------------------------------------------------------------------------- /include/str.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef STR_INCLUDED 3 | #define STR_INCLUDED 4 | #include 5 | #include "fmt.h" 6 | extern char *Str_sub(const char *s, int i, int j); 7 | extern char *Str_dup(const char *s, int i, int j, int n); 8 | extern char *Str_cat(const char *s1, int i1, int j1, 9 | const char *s2, int i2, int j2); 10 | extern char *Str_catv (const char *s, ...); 11 | extern char *Str_reverse(const char *s, int i, int j); 12 | extern char *Str_map (const char *s, int i, int j, 13 | const char *from, const char *to); 14 | extern int Str_pos(const char *s, int i); 15 | extern int Str_len(const char *s, int i, int j); 16 | extern int Str_cmp(const char *s1, int i1, int j1, 17 | const char *s2, int i2, int j2); 18 | extern int Str_chr (const char *s, int i, int j, int c); 19 | extern int Str_rchr (const char *s, int i, int j, int c); 20 | extern int Str_upto (const char *s, int i, int j, 21 | const char *set); 22 | extern int Str_rupto(const char *s, int i, int j, 23 | const char *set); 24 | extern int Str_find (const char *s, int i, int j, 25 | const char *str); 26 | extern int Str_rfind(const char *s, int i, int j, 27 | const char *str); 28 | extern int Str_any (const char *s, int i, 29 | const char *set); 30 | extern int Str_many (const char *s, int i, int j, 31 | const char *set); 32 | extern int Str_rmany (const char *s, int i, int j, 33 | const char *set); 34 | extern int Str_match (const char *s, int i, int j, 35 | const char *str); 36 | extern int Str_rmatch(const char *s, int i, int j, 37 | const char *str); 38 | extern void Str_fmt(int code, va_list_box *box, 39 | int put(int c, void *cl), void *cl, 40 | unsigned char flags[], int width, int precision); 41 | #undef T 42 | #endif 43 | -------------------------------------------------------------------------------- /include/table.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef TABLE_INCLUDED 3 | #define TABLE_INCLUDED 4 | #define T Table_T 5 | typedef struct T *T; 6 | extern T Table_new (int hint, 7 | int cmp(const void *x, const void *y), 8 | unsigned hash(const void *key)); 9 | extern void Table_free(T *table); 10 | extern int Table_length(T table); 11 | extern void *Table_put (T table, const void *key, 12 | void *value); 13 | extern void *Table_get (T table, const void *key); 14 | extern void *Table_remove(T table, const void *key); 15 | extern void Table_map (T table, 16 | void apply(const void *key, void **value, void *cl), 17 | void *cl); 18 | extern void **Table_toArray(T table, void *end); 19 | #undef T 20 | #endif 21 | -------------------------------------------------------------------------------- /include/text.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef TEXT_INCLUDED 3 | #define TEXT_INCLUDED 4 | #include 5 | #include "fmt.h" 6 | #define T Text_T 7 | typedef struct T { 8 | int len; 9 | const char *str; 10 | } T; 11 | typedef struct Text_save_T *Text_save_T; 12 | extern const T Text_cset; 13 | extern const T Text_ascii; 14 | extern const T Text_ucase; 15 | extern const T Text_lcase; 16 | extern const T Text_digits; 17 | extern const T Text_null; 18 | extern T Text_put(const char *str); 19 | extern char *Text_get(char *str, int size, T s); 20 | extern T Text_box(const char *str, int len); 21 | extern T Text_sub(T s, int i, int j); 22 | extern int Text_pos(T s, int i); 23 | extern T Text_cat (T s1, T s2); 24 | extern T Text_dup (T s, int n); 25 | extern T Text_reverse(T s); 26 | extern T Text_map(T s, const T *from, const T *to); 27 | extern int Text_cmp(T s1, T s2); 28 | extern int Text_chr (T s, int i, int j, int c); 29 | extern int Text_rchr (T s, int i, int j, int c); 30 | extern int Text_upto (T s, int i, int j, T set); 31 | extern int Text_rupto(T s, int i, int j, T set); 32 | extern int Text_any (T s, int i, T set); 33 | extern int Text_many (T s, int i, int j, T set); 34 | extern int Text_rmany(T s, int i, int j, T set); 35 | extern int Text_find (T s, int i, int j, T str); 36 | extern int Text_rfind (T s, int i, int j, T str); 37 | extern int Text_match (T s, int i, int j, T str); 38 | extern int Text_rmatch(T s, int i, int j, T str); 39 | extern void Text_fmt(int code, va_list_box *box, 40 | int put(int c, void *cl), void *cl, 41 | unsigned char flags[], int width, int precision); 42 | extern Text_save_T Text_save(void); 43 | extern void Text_restore(Text_save_T *save); 44 | #undef T 45 | #endif 46 | -------------------------------------------------------------------------------- /include/thread.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef THREAD_INCLUDED 3 | #define THREAD_INCLUDED 4 | #include "except.h" 5 | #define T Thread_T 6 | typedef struct T *T; 7 | extern const Except_T Thread_Failed; 8 | extern const Except_T Thread_Alerted; 9 | extern int Thread_init (int preempt, ...); 10 | extern T Thread_new (int apply(void *), 11 | void *args, int nbytes, ...); 12 | extern void Thread_exit (int code); 13 | extern void Thread_alert(T t); 14 | extern T Thread_self (void); 15 | extern int Thread_join (T t); 16 | extern void Thread_pause(void); 17 | #undef T 18 | #endif 19 | -------------------------------------------------------------------------------- /include/xp.h: -------------------------------------------------------------------------------- 1 | /* $Id$ */ 2 | #ifndef XP_INCLUDED 3 | #define XP_INCLUDED 4 | #define T XP_T 5 | typedef unsigned char *T; 6 | extern int XP_add(int n, T z, T x, T y, int carry); 7 | extern int XP_sub(int n, T z, T x, T y, int borrow); 8 | extern int XP_mul(T z, int n, T x, int m, T y); 9 | extern int XP_div(int n, T q, T x, int m, T y, T r,T tmp); 10 | extern int XP_sum (int n, T z, T x, int y); 11 | extern int XP_diff (int n, T z, T x, int y); 12 | extern int XP_product (int n, T z, T x, int y); 13 | extern int XP_quotient(int n, T z, T x, int y); 14 | extern int XP_neg(int n, T z, T x, int carry); 15 | extern int XP_cmp(int n, T x, T y); 16 | extern void XP_lshift(int n, T z, int m, T x, 17 | int s, int fill); 18 | extern void XP_rshift(int n, T z, int m, T x, 19 | int s, int fill); 20 | extern int XP_length (int n, T x); 21 | extern unsigned long XP_fromint(int n, T z, 22 | unsigned long u); 23 | extern unsigned long XP_toint (int n, T x); 24 | extern int XP_fromstr(int n, T z, const char *str, 25 | int base, char **end); 26 | extern char *XP_tostr (char *str, int size, int base, 27 | int n, T x); 28 | #undef T 29 | #endif 30 | -------------------------------------------------------------------------------- /makefile.nt: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | BUILDDIR=^\lib^\cii^\1 3 | A=.lib 4 | O=.obj 5 | E=.exe 6 | I=include 7 | CC=cl -nologo -DWIN32 8 | B=$(BUILDDIR)^\ 9 | CFLAGS=-Zi -MTd -I$I 10 | LD=cl -nologo 11 | LDFLAGS=-Zi -MTd 12 | THREADS=$Bthread-nt$O $Bchan$O 13 | EXTRAS= 14 | 15 | # $Id$ 16 | OBJS= $Bap$O \ 17 | $Barena$O \ 18 | $Barith$O \ 19 | $Barray$O \ 20 | $Bassert$O \ 21 | $Batom$O \ 22 | $Bbit$O \ 23 | $Bexcept$O \ 24 | $Bfmt$O \ 25 | $Blist$O \ 26 | $Bmem$O \ 27 | $Bmp$O \ 28 | $Bring$O \ 29 | $Bseq$O \ 30 | $Bset$O \ 31 | $Bstack$O \ 32 | $Bstr$O \ 33 | $Btable$O \ 34 | $Btext$O \ 35 | $Bxp$O \ 36 | $(THREADS) 37 | 38 | EXAMPLES= $Bdouble$E \ 39 | $Bcalc$E \ 40 | $Bids$E \ 41 | $Bmpcalc$E \ 42 | $Bwf$E \ 43 | $Bxref$E \ 44 | $Bcref$E \ 45 | $Biref$E \ 46 | $Bkref$E \ 47 | $Bidents$E \ 48 | $Bwords$E \ 49 | $Bbasename$E \ 50 | $Bdirname$E \ 51 | $Bsort$E \ 52 | $Bspin$E \ 53 | $Bsieve$E 54 | 55 | all:: $Blibcii$A $(EXAMPLES) $Bmemchk$O 56 | 57 | $Blibcii$A:: $(OBJS) $(EXTRAS) 58 | lib -nologo -out:$@ $(OBJS) $(EXTRAS) 59 | 60 | $Bap$O: src/ap.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/ap.c 61 | $Barena$O: src/arena.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/arena.c 62 | $Barith$O: src/arith.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/arith.c 63 | $Barray$O: src/array.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/array.c 64 | $Bassert$O: src/assert.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/assert.c 65 | $Batom$O: src/atom.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/atom.c 66 | $Bbit$O: src/bit.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/bit.c 67 | $Bchan$O: src/chan.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/chan.c 68 | $Bexcept$O: src/except.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/except.c 69 | $Bfmt$O: src/fmt.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/fmt.c 70 | $Blist$O: src/list.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/list.c 71 | $Bmem$O: src/mem.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/mem.c 72 | $Bmemchk$O: src/memchk.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/memchk.c 73 | $Bmp$O: src/mp.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/mp.c 74 | $Bring$O: src/ring.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/ring.c 75 | $Bseq$O: src/seq.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/seq.c 76 | $Bset$O: src/set.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/set.c 77 | $Bstack$O: src/stack.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/stack.c 78 | $Bstr$O: src/str.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/str.c 79 | $Btable$O: src/table.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/table.c 80 | $Btext$O: src/text.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/text.c 81 | $Bthread$O: src/thread.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/thread.c 82 | $Bthread-nt$O: src/thread-nt.c;$(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/thread-nt.c 83 | $Bxp$O: src/xp.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/xp.c 84 | $Bswtch$O: src/swtch.s; as(,src/swtch.s,$@) 85 | 86 | $Bmemcmp$O: src/memcmp.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/memcmp.c 87 | $Bmemmove$O: src/memmove.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/memmove.c 88 | $Bstrncmp$O: src/strncmp.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$Blibcii.pdb src/strncmp.c 89 | 90 | $Bdouble$O: examples/double.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/double.c 91 | $Bcalc$O: examples/calc.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/calc.c 92 | $Bids$O: examples/ids.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/ids.c 93 | $Bmpcalc$O: examples/mpcalc.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/mpcalc.c 94 | $Biref$O: examples/iref.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/iref.c 95 | $Bkref$O: examples/kref.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/kref.c 96 | $Bidents$O: examples/idents.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/idents.c 97 | $Bwords$O: examples/words.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/words.c 98 | $Bbasename$O: examples/basename.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/basename.c 99 | $Bwf$O: examples/wf.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/wf.c 100 | $Bgetword$O: examples/getword.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/getword.c 101 | $Bxref$O: examples/xref.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/xref.c 102 | $Binteger$O: examples/integer.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/integer.c 103 | $Bcref$O: examples/cref.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/cref.c 104 | $Bsort$O: examples/sort.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/sort.c 105 | $Bspin$O: examples/spin.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/spin.c 106 | $Bsieve$O: examples/sieve.c; $(CC) $(CFLAGS) -c -Fo$@ -Fd$B examples/sieve.c 107 | 108 | $Bwf$O $Bxref$O $Bgetword$O: examples/getword.h 109 | $Bcref$O $Binteger$O: examples/integer.h 110 | 111 | $Bdouble$E: $Bdouble$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bdouble$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 112 | $Bcalc$E: $Bcalc$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bcalc$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 113 | $Bids$E: $Bids$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bids$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 114 | $Bmpcalc$E: $Bmpcalc$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bmpcalc$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 115 | $Biref$E: $Biref$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Biref$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 116 | $Bkref$E: $Bkref$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bkref$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 117 | $Bidents$E: $Bidents$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bidents$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 118 | $Bwords$E: $Bwords$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bwords$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 119 | $Bbasename$E: $Bbasename$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bbasename$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 120 | $Bdirname$E: $Bbasename$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bbasename$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 121 | $Bwf$E: $Bwf$O $Bgetword$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bwf$O $Bgetword$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 122 | $Bxref$E: $Bxref$O $Bgetword$O $Blibcii$A;$(LD) $(LDFLAGS) -Fe$@ $Bxref$O $Bgetword$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 123 | $Bcref$E: $Bcref$O $Binteger$O $Blibcii$A;$(LD) $(LDFLAGS) -Fe$@ $Bcref$O $Binteger$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 124 | $Bsort$E: $Bsort$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bsort$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 125 | $Bspin$E: $Bspin$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bspin$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 126 | $Bsieve$E: $Bsieve$O $Blibcii$A; $(LD) $(LDFLAGS) -Fe$@ $Bsieve$O $Blibcii$A -link /NODEFAULTLIB:libc.lib 127 | 128 | clean:: 129 | -del /q $B*$O 130 | -del /q $(EXAMPLES) 131 | 132 | clobber:: clean 133 | -del /q $Blibcii$A 134 | 135 | libcii.dll: $Blibcii.dll 136 | 137 | $Blibcii.dll: $(OBJS) $(EXTRAS) 138 | link -dll -out:$@ -def:src/libcii.def $(OBJS) $(EXTRAS) 139 | 140 | clean:: 141 | -del /q $B*.ilk *.pdb 142 | -move $Blibcii.pdb $Blibcii.bak 143 | -del /q $B*.pdb 144 | -move $Blibcii.bak $Blibcii.pdb 145 | 146 | clobber:: 147 | -del /q $Blibcii.dll $Blibcii.exp 148 | 149 | 150 | # DO NOT DELETE THIS LINE -- make depend depends on it. 151 | 152 | $Bap$O: $I/assert.h $I/except.h $I/ap.h $I/fmt.h $I/xp.h $I/mem.h 153 | $Barena$O: $I/assert.h $I/except.h $I/arena.h 154 | $Barith$O: $I/arith.h 155 | $Barray$O: $I/assert.h $I/except.h $I/array.h $I/arrayrep.h $I/mem.h 156 | $Bassert$O: $I/assert.h $I/except.h 157 | $Batom$O: $I/atom.h $I/assert.h $I/except.h $I/mem.h 158 | $Bbit$O: $I/assert.h $I/except.h $I/bit.h $I/mem.h 159 | $Bchan$O: $I/assert.h $I/except.h $I/mem.h $I/chan.h $I/sem.h 160 | $Bexcept$O: $I/assert.h $I/except.h 161 | $Bfmt$O: $I/assert.h $I/except.h $I/fmt.h $I/mem.h 162 | $Blist$O: $I/assert.h $I/except.h $I/mem.h $I/list.h 163 | $Bmem$O: $I/assert.h $I/except.h $I/mem.h 164 | $Bmemchk$O: $I/assert.h $I/except.h $I/mem.h 165 | $Bmp$O: $I/assert.h $I/except.h $I/fmt.h $I/mem.h $I/xp.h $I/mp.h 166 | $Bring$O: $I/assert.h $I/except.h $I/ring.h $I/mem.h 167 | $Bseq$O: $I/assert.h $I/except.h $I/seq.h $I/array.h $I/arrayrep.h $I/mem.h 168 | $Bset$O: $I/mem.h $I/except.h $I/assert.h $I/arith.h $I/set.h 169 | $Bstack$O: $I/assert.h $I/except.h $I/mem.h $I/stack.h 170 | $Bstr$O: $I/assert.h $I/except.h $I/fmt.h $I/str.h $I/mem.h 171 | $Btable$O: $I/mem.h $I/except.h $I/assert.h $I/table.h 172 | $Btext$O: $I/assert.h $I/except.h $I/fmt.h $I/text.h $I/mem.h 173 | $Bthread$O: $I/assert.h $I/except.h $I/mem.h $I/thread.h $I/sem.h 174 | $Bthread-nt$O: $I/assert.h $I/except.h $I/mem.h $I/thread.h $I/sem.h 175 | $Bxp$O: $I/assert.h $I/except.h $I/xp.h 176 | -------------------------------------------------------------------------------- /misc/Makefile.am: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kev009/cii/4af8d6185f34fbc103085ab6dbb080aa93a99318/misc/Makefile.am -------------------------------------------------------------------------------- /misc/custom.mk.old: -------------------------------------------------------------------------------- 1 | #empty 2 | -------------------------------------------------------------------------------- /misc/makefile.old: -------------------------------------------------------------------------------- 1 | # $Id$ 2 | MAJORVERSION=2 3 | A=.a 4 | O=.o 5 | SO=.so 6 | E= 7 | CC=cc 8 | I=include 9 | CFLAGS=-g -I$I 10 | LDFLAGS=-g 11 | LD=cc 12 | AS=as 13 | AR=ar ruv 14 | RANLIB=ranlib 15 | DIFF=diff 16 | RM=rm -f 17 | CUSTOM=custom.mk 18 | EXTRAS=$(BUILDDIR)memcmp$O $(BUILDDIR)memmove$O $(BUILDDIR)strncmp$O 19 | THREADS=$(BUILDDIR)thread$O $(BUILDDIR)swtch$O $(BUILDDIR)chan$O 20 | include $(CUSTOM) 21 | B=$(BUILDDIR) 22 | 23 | OBJS= $Bap$O \ 24 | $Barena$O \ 25 | $Barith$O \ 26 | $Barray$O \ 27 | $Bassert$O \ 28 | $Batom$O \ 29 | $Bbit$O \ 30 | $Bexcept$O \ 31 | $Bfmt$O \ 32 | $Blist$O \ 33 | $Bmem$O \ 34 | $Bmp$O \ 35 | $Bring$O \ 36 | $Bseq$O \ 37 | $Bset$O \ 38 | $Bstack$O \ 39 | $Bstr$O \ 40 | $Btable$O \ 41 | $Btext$O \ 42 | $Bxp$O \ 43 | $(THREADS) 44 | 45 | EXAMPLES= $Bdouble$E \ 46 | $Bcalc$E \ 47 | $Bids$E \ 48 | $Bmpcalc$E \ 49 | $Bwf$E \ 50 | $Bxref$E \ 51 | $Bcref$E \ 52 | $Biref$E \ 53 | $Bkref$E \ 54 | $Bidents$E \ 55 | $Bwords$E \ 56 | $Bbasename$E \ 57 | $Bdirname$E \ 58 | $Bsort$E \ 59 | $Bspin$E \ 60 | $Bsieve$E 61 | 62 | all:: $Blibcii$A $(EXAMPLES) $Bmemchk$O 63 | 64 | $Blibcii$A:: $(OBJS) $(EXTRAS) 65 | $(AR) $@ $(OBJS) $(EXTRAS); $(RANLIB) $@ || true 66 | 67 | # Linux-specific rule for building a shared library 68 | $Blibcii$(SO).$(MAJORVERSION): $(OBJS) $(EXTRAS) 69 | $(CC) -shared -Wl,-soname,libcii$(SO).$(MAJORVERSION) -o $@ $(OBJS) $(EXTRAS) 70 | 71 | $Bap$O: src/ap.c; $(CC) $(CFLAGS) -c -o $@ src/ap.c 72 | $Barena$O: src/arena.c; $(CC) $(CFLAGS) -c -o $@ src/arena.c 73 | $Barith$O: src/arith.c; $(CC) $(CFLAGS) -c -o $@ src/arith.c 74 | $Barray$O: src/array.c; $(CC) $(CFLAGS) -c -o $@ src/array.c 75 | $Bassert$O: src/assert.c; $(CC) $(CFLAGS) -c -o $@ src/assert.c 76 | $Batom$O: src/atom.c; $(CC) $(CFLAGS) -c -o $@ src/atom.c 77 | $Bbit$O: src/bit.c; $(CC) $(CFLAGS) -c -o $@ src/bit.c 78 | $Bchan$O: src/chan.c; $(CC) $(CFLAGS) -c -o $@ src/chan.c 79 | $Bexcept$O: src/except.c; $(CC) $(CFLAGS) -c -o $@ src/except.c 80 | $Bfmt$O: src/fmt.c; $(CC) $(CFLAGS) -c -o $@ src/fmt.c 81 | $Blist$O: src/list.c; $(CC) $(CFLAGS) -c -o $@ src/list.c 82 | $Bmem$O: src/mem.c; $(CC) $(CFLAGS) -c -o $@ src/mem.c 83 | $Bmemchk$O: src/memchk.c; $(CC) $(CFLAGS) -c -o $@ src/memchk.c 84 | $Bmp$O: src/mp.c; $(CC) $(CFLAGS) -c -o $@ src/mp.c 85 | $Bring$O: src/ring.c; $(CC) $(CFLAGS) -c -o $@ src/ring.c 86 | $Bseq$O: src/seq.c; $(CC) $(CFLAGS) -c -o $@ src/seq.c 87 | $Bset$O: src/set.c; $(CC) $(CFLAGS) -c -o $@ src/set.c 88 | $Bstack$O: src/stack.c; $(CC) $(CFLAGS) -c -o $@ src/stack.c 89 | $Bstr$O: src/str.c; $(CC) $(CFLAGS) -c -o $@ src/str.c 90 | $Btable$O: src/table.c; $(CC) $(CFLAGS) -c -o $@ src/table.c 91 | $Btext$O: src/text.c; $(CC) $(CFLAGS) -c -o $@ src/text.c 92 | $Bthread$O: src/thread.c; $(CC) $(CFLAGS) -c -o $@ src/thread.c 93 | $Bthread-nt$O: src/thread-nt.c;$(CC) $(CFLAGS) -c -o $@ src/thread-nt.c 94 | $Bxp$O: src/xp.c; $(CC) $(CFLAGS) -c -o $@ src/xp.c 95 | $Bswtch$O: src/swtch.s; $(AS) -o $@ src/swtch.s 96 | 97 | $Bmemcmp$O: src/memcmp.c; $(CC) $(CFLAGS) -c -o $@ src/memcmp.c 98 | $Bmemmove$O: src/memmove.c; $(CC) $(CFLAGS) -c -o $@ src/memmove.c 99 | $Bstrncmp$O: src/strncmp.c; $(CC) $(CFLAGS) -c -o $@ src/strncmp.c 100 | 101 | $Bdouble$O: examples/double.c; $(CC) $(CFLAGS) -c -o $@ examples/double.c 102 | $Bcalc$O: examples/calc.c; $(CC) $(CFLAGS) -c -o $@ examples/calc.c 103 | $Bids$O: examples/ids.c; $(CC) $(CFLAGS) -c -o $@ examples/ids.c 104 | $Bmpcalc$O: examples/mpcalc.c; $(CC) $(CFLAGS) -c -o $@ examples/mpcalc.c 105 | $Biref$O: examples/iref.c; $(CC) $(CFLAGS) -c -o $@ examples/iref.c 106 | $Bkref$O: examples/kref.c; $(CC) $(CFLAGS) -c -o $@ examples/kref.c 107 | $Bidents$O: examples/idents.c; $(CC) $(CFLAGS) -c -o $@ examples/idents.c 108 | $Bwords$O: examples/words.c; $(CC) $(CFLAGS) -c -o $@ examples/words.c 109 | $Bbasename$O: examples/basename.c; $(CC) $(CFLAGS) -c -o $@ examples/basename.c 110 | $Bwf$O: examples/wf.c; $(CC) $(CFLAGS) -c -o $@ examples/wf.c 111 | $Bgetword$O: examples/getword.c; $(CC) $(CFLAGS) -c -o $@ examples/getword.c 112 | $Bxref$O: examples/xref.c; $(CC) $(CFLAGS) -c -o $@ examples/xref.c 113 | $Binteger$O: examples/integer.c; $(CC) $(CFLAGS) -c -o $@ examples/integer.c 114 | $Bcref$O: examples/cref.c; $(CC) $(CFLAGS) -c -o $@ examples/cref.c 115 | $Bsort$O: examples/sort.c; $(CC) $(CFLAGS) -c -o $@ examples/sort.c 116 | $Bspin$O: examples/spin.c; $(CC) $(CFLAGS) -c -o $@ examples/spin.c 117 | $Bsieve$O: examples/sieve.c; $(CC) $(CFLAGS) -c -o $@ examples/sieve.c 118 | 119 | $Bwf$O $Bxref$O $Bgetword$O: examples/getword.h 120 | $Bcref$O $Binteger$O: examples/integer.h 121 | 122 | $Bdouble$E: $Bdouble$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bdouble$O $Blibcii$A 123 | $Bcalc$E: $Bcalc$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bcalc$O $Blibcii$A 124 | $Bids$E: $Bids$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bids$O $Blibcii$A 125 | $Bmpcalc$E: $Bmpcalc$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bmpcalc$O $Blibcii$A 126 | $Biref$E: $Biref$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Biref$O $Blibcii$A 127 | $Bkref$E: $Bkref$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bkref$O $Blibcii$A 128 | $Bidents$E: $Bidents$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bidents$O $Blibcii$A 129 | $Bwords$E: $Bwords$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bwords$O $Blibcii$A 130 | $Bbasename$E: $Bbasename$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bbasename$O $Blibcii$A 131 | $Bdirname$E: $Bbasename$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bbasename$O $Blibcii$A 132 | $Bwf$E: $Bwf$O $Bgetword$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bwf$O $Bgetword$O $Blibcii$A 133 | $Bxref$E: $Bxref$O $Bgetword$O $Blibcii$A;$(LD) $(LDFLAGS) -o $@ $Bxref$O $Bgetword$O $Blibcii$A 134 | $Bcref$E: $Bcref$O $Binteger$O $Blibcii$A;$(LD) $(LDFLAGS) -o $@ $Bcref$O $Binteger$O $Blibcii$A 135 | $Bsort$E: $Bsort$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bsort$O $Blibcii$A 136 | $Bspin$E: $Bspin$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bspin$O $Blibcii$A 137 | $Bsieve$E: $Bsieve$O $Blibcii$A; $(LD) $(LDFLAGS) -o $@ $Bsieve$O $Blibcii$A 138 | 139 | maxalign: $Bmaxalign$E 140 | $Bmaxalign$E 141 | 142 | $Bmaxalign$E: misc/maxalign.c 143 | $(CC) -o $@ misc/maxalign.c 144 | 145 | clean:: 146 | $(RM) $B*$O 147 | $(RM) $(EXAMPLES) 148 | 149 | clobber:: clean 150 | $(RM) $Blibcii$A 151 | 152 | 153 | 154 | # DO NOT DELETE THIS LINE -- make depend depends on it. 155 | 156 | $Bap$O: $I/assert.h $I/except.h $I/ap.h $I/fmt.h $I/xp.h $I/mem.h 157 | $Barena$O: $I/assert.h $I/except.h $I/arena.h 158 | $Barith$O: $I/arith.h 159 | $Barray$O: $I/assert.h $I/except.h $I/array.h $I/arrayrep.h $I/mem.h 160 | $Bassert$O: $I/assert.h $I/except.h 161 | $Batom$O: $I/atom.h $I/assert.h $I/except.h $I/mem.h 162 | $Bbit$O: $I/assert.h $I/except.h $I/bit.h $I/mem.h 163 | $Bchan$O: $I/assert.h $I/except.h $I/mem.h $I/chan.h $I/sem.h 164 | $Bexcept$O: $I/assert.h $I/except.h 165 | $Bfmt$O: $I/assert.h $I/except.h $I/fmt.h $I/mem.h 166 | $Blist$O: $I/assert.h $I/except.h $I/mem.h $I/list.h 167 | $Bmem$O: $I/assert.h $I/except.h $I/mem.h 168 | $Bmemchk$O: $I/assert.h $I/except.h $I/mem.h 169 | $Bmp$O: $I/assert.h $I/except.h $I/fmt.h $I/mem.h $I/xp.h $I/mp.h 170 | $Bring$O: $I/assert.h $I/except.h $I/ring.h $I/mem.h 171 | $Bseq$O: $I/assert.h $I/except.h $I/seq.h $I/array.h $I/arrayrep.h $I/mem.h 172 | $Bset$O: $I/mem.h $I/except.h $I/assert.h $I/arith.h $I/set.h 173 | $Bstack$O: $I/assert.h $I/except.h $I/mem.h $I/stack.h 174 | $Bstr$O: $I/assert.h $I/except.h $I/fmt.h $I/str.h $I/mem.h 175 | $Btable$O: $I/mem.h $I/except.h $I/assert.h $I/table.h 176 | $Btext$O: $I/assert.h $I/except.h $I/fmt.h $I/text.h $I/mem.h 177 | $Bthread$O: $I/assert.h $I/except.h $I/mem.h $I/thread.h $I/sem.h 178 | $Bthread-nt$O: $I/assert.h $I/except.h $I/mem.h $I/thread.h $I/sem.h 179 | $Bxp$O: $I/assert.h $I/except.h $I/xp.h 180 | -------------------------------------------------------------------------------- /misc/maxalign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | /* 7 | On most platforms, malloc returns pointers to blocks that are 8 | aligned on addresses that are multiples of the size of the largest 9 | basic data type. Some CII functions use a union to determine this 10 | multiple (cf. union align on p. 80). Alignments are less restrictive 11 | on some platforms and, for these, MAXALIGN must be defined as the 12 | alignment required. 13 | 14 | This program attempts to determine the correct value for MAXALIGN, if 15 | one is necessary, and echo the appropriate -D option. 16 | The method used relies on the C compiler using the same alignments as 17 | malloc, which is not required. malloc is the final authority: If it 18 | returns addresses that are multiples of sizeof (union align), then 19 | MAXALIGN is unnecessary; otherwise, MAXALIGN must provide the 20 | alignment. malloc(1) is called to determine if the address it returns 21 | has an alignment less strict than that used by the C compiler. 22 | 23 | Incorrect values of MAXALIGN can cause crashes and assertion failures. 24 | */ 25 | union align { 26 | int i; 27 | long l; 28 | long *lp; 29 | void *p; 30 | void (*fp)(void); 31 | float f; 32 | double d; 33 | long double ld; 34 | }; 35 | 36 | typedef void (*functp); 37 | #define yy \ 38 | xx(int,i);\ 39 | xx(long,l);\ 40 | xx(long *,lp);\ 41 | xx(void *,p);\ 42 | xx(functp,fp);\ 43 | xx(float,f);\ 44 | xx(double,d);\ 45 | xx(long double,ld); 46 | 47 | int main(int argc, char *argv[]) { 48 | #define xx(t,v) struct { char pad; t v; } v 49 | yy 50 | #undef xx 51 | unsigned max = 0; 52 | int verbose = 0; 53 | 54 | #define xx(t,v) if ((char *)&v.v - &v.pad > max) max = (char *)&v.v - &v.pad 55 | yy 56 | #undef xx 57 | if (argc > 1 && strcmp(argv[1], "-v") == 0) 58 | verbose = 1; 59 | if (verbose) 60 | fprintf(stderr, "sizeof (union align) = %u\n", sizeof (union align)); 61 | assert(max); 62 | 63 | char *ptr = malloc(1); 64 | if (verbose) 65 | fprintf(stderr, "malloc(1) = %p\n", ptr); 66 | while (max > 0 && ((unsigned)ptr)%max != 0) 67 | max /= 2; 68 | assert(max); 69 | 70 | if (max != sizeof (union align)) 71 | printf("-DMAXALIGN=%u\n", max); 72 | return EXIT_SUCCESS; 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include 2 | 3 | lib_LTLIBRARIES = libcii.la 4 | libcii_la_includedir = $(top_srcdir)/include 5 | libcii_la_SOURCES = ap.c \ 6 | arena.c \ 7 | arith.c \ 8 | array.c \ 9 | assert.c \ 10 | atom.c \ 11 | bit.c \ 12 | chan.c \ 13 | except.c \ 14 | fmt.c \ 15 | list.c \ 16 | mem.c \ 17 | mp.c \ 18 | ring.c \ 19 | seq.c \ 20 | set.c \ 21 | stack.c \ 22 | str.c \ 23 | table.c \ 24 | text.c \ 25 | xp.c 26 | # Needs work: 27 | #memchk.c 28 | #thread.c 29 | #thread-nt.c 30 | #swtch.s 31 | 32 | # Conditional 33 | # memcmp.c 34 | # memmove.c 35 | # strncmp.c 36 | 37 | libcii_la_CPPFLAGS = -I$(top_srcdir)/include 38 | libcii_la_LDFLAGS = -version-info 2:0:0 39 | -------------------------------------------------------------------------------- /src/ap.c: -------------------------------------------------------------------------------- 1 | static const char *rcsid = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "assert.h" 7 | #include "ap.h" 8 | #include "fmt.h" 9 | #include "xp.h" 10 | #include "mem.h" 11 | #define T AP_T 12 | struct T { 13 | int sign; 14 | int ndigits; 15 | int size; 16 | XP_T digits; 17 | }; 18 | #define iszero(x) ((x)->ndigits==1 && (x)->digits[0]==0) 19 | #define maxdigits(x,y) ((x)->ndigits > (y)->ndigits ? \ 20 | (x)->ndigits : (y)->ndigits) 21 | #define isone(x) ((x)->ndigits==1 && (x)->digits[0]==1) 22 | static T normalize(T z, int n); 23 | static int cmp(T x, T y); 24 | static T mk(int size) { 25 | T z = CALLOC(1, sizeof (*z) + size); 26 | assert(size > 0); 27 | z->sign = 1; 28 | z->size = size; 29 | z->ndigits = 1; 30 | z->digits = (XP_T)(z + 1); 31 | return z; 32 | } 33 | static T set(T z, long int n) { 34 | if (n == LONG_MIN) 35 | XP_fromint(z->size, z->digits, LONG_MAX + 1UL); 36 | else if (n < 0) 37 | XP_fromint(z->size, z->digits, -n); 38 | else 39 | XP_fromint(z->size, z->digits, n); 40 | z->sign = n < 0 ? -1 : 1; 41 | return normalize(z, z->size); 42 | } 43 | static T normalize(T z, int n) { 44 | z->ndigits = XP_length(n, z->digits); 45 | return z; 46 | } 47 | static T add(T z, T x, T y) { 48 | int n = y->ndigits; 49 | if (x->ndigits < n) 50 | return add(z, y, x); 51 | else if (x->ndigits > n) { 52 | int carry = XP_add(n, z->digits, x->digits, 53 | y->digits, 0); 54 | z->digits[z->size-1] = XP_sum(x->ndigits - n, 55 | &z->digits[n], &x->digits[n], carry); 56 | } else 57 | z->digits[n] = XP_add(n, z->digits, x->digits, 58 | y->digits, 0); 59 | return normalize(z, z->size); 60 | } 61 | static T sub(T z, T x, T y) { 62 | int borrow, n = y->ndigits; 63 | borrow = XP_sub(n, z->digits, x->digits, 64 | y->digits, 0); 65 | if (x->ndigits > n) 66 | borrow = XP_diff(x->ndigits - n, &z->digits[n], 67 | &x->digits[n], borrow); 68 | assert(borrow == 0); 69 | return normalize(z, z->size); 70 | } 71 | static T mulmod(T x, T y, T p) { 72 | T z, xy = AP_mul(x, y); 73 | z = AP_mod(xy, p); 74 | AP_free(&xy); 75 | return z; 76 | } 77 | static int cmp(T x, T y) { 78 | if (x->ndigits != y->ndigits) 79 | return x->ndigits - y->ndigits; 80 | else 81 | return XP_cmp(x->ndigits, x->digits, y->digits); 82 | } 83 | T AP_new(long int n) { 84 | return set(mk(sizeof (long int)), n); 85 | } 86 | void AP_free(T *z) { 87 | assert(z && *z); 88 | FREE(*z); 89 | } 90 | T AP_neg(T x) { 91 | T z; 92 | assert(x); 93 | z = mk(x->ndigits); 94 | memcpy(z->digits, x->digits, x->ndigits); 95 | z->ndigits = x->ndigits; 96 | z->sign = iszero(z) ? 1 : -x->sign; 97 | return z; 98 | } 99 | T AP_mul(T x, T y) { 100 | T z; 101 | assert(x); 102 | assert(y); 103 | z = mk(x->ndigits + y->ndigits); 104 | XP_mul(z->digits, x->ndigits, x->digits, y->ndigits, 105 | y->digits); 106 | normalize(z, z->size); 107 | z->sign = iszero(z) 108 | || ((x->sign^y->sign) == 0) ? 1 : -1; 109 | return z; 110 | } 111 | T AP_add(T x, T y) { 112 | T z; 113 | assert(x); 114 | assert(y); 115 | if (((x->sign^y->sign) == 0)) { 116 | z = add(mk(maxdigits(x,y) + 1), x, y); 117 | z->sign = iszero(z) ? 1 : x->sign; 118 | } else 119 | if (cmp(x, y) > 0) { 120 | z = sub(mk(x->ndigits), x, y); 121 | z->sign = iszero(z) ? 1 : x->sign; 122 | } 123 | else { 124 | z = sub(mk(y->ndigits), y, x); 125 | z->sign = iszero(z) ? 1 : -x->sign; 126 | } 127 | return z; 128 | } 129 | T AP_sub(T x, T y) { 130 | T z; 131 | assert(x); 132 | assert(y); 133 | if (!((x->sign^y->sign) == 0)) { 134 | z = add(mk(maxdigits(x,y) + 1), x, y); 135 | z->sign = iszero(z) ? 1 : x->sign; 136 | } else 137 | if (cmp(x, y) > 0) { 138 | z = sub(mk(x->ndigits), x, y); 139 | z->sign = iszero(z) ? 1 : x->sign; 140 | } else { 141 | z = sub(mk(y->ndigits), y, x); 142 | z->sign = iszero(z) ? 1 : -x->sign; 143 | } 144 | return z; 145 | } 146 | T AP_div(T x, T y) { 147 | T q, r; 148 | assert(x); 149 | assert(y); 150 | assert(!iszero(y)); 151 | q = mk(x->ndigits); 152 | r = mk(y->ndigits); 153 | { 154 | XP_T tmp = ALLOC(x->ndigits + y->ndigits + 2); 155 | XP_div(x->ndigits, q->digits, x->digits, 156 | y->ndigits, y->digits, r->digits, tmp); 157 | FREE(tmp); 158 | } 159 | normalize(q, q->size); 160 | normalize(r, r->size); 161 | q->sign = iszero(q) 162 | || ((x->sign^y->sign) == 0) ? 1 : -1; 163 | if (!((x->sign^y->sign) == 0) && !iszero(r)) { 164 | int carry = XP_sum(q->size, q->digits, 165 | q->digits, 1); 166 | assert(carry == 0); 167 | normalize(q, q->size); 168 | } 169 | AP_free(&r); 170 | return q; 171 | } 172 | T AP_mod(T x, T y) { 173 | T q, r; 174 | assert(x); 175 | assert(y); 176 | assert(!iszero(y)); 177 | q = mk(x->ndigits); 178 | r = mk(y->ndigits); 179 | { 180 | XP_T tmp = ALLOC(x->ndigits + y->ndigits + 2); 181 | XP_div(x->ndigits, q->digits, x->digits, 182 | y->ndigits, y->digits, r->digits, tmp); 183 | FREE(tmp); 184 | } 185 | normalize(q, q->size); 186 | normalize(r, r->size); 187 | q->sign = iszero(q) 188 | || ((x->sign^y->sign) == 0) ? 1 : -1; 189 | if (!((x->sign^y->sign) == 0) && !iszero(r)) { 190 | int borrow = XP_sub(r->size, r->digits, 191 | y->digits, r->digits, 0); 192 | assert(borrow == 0); 193 | normalize(r, r->size); 194 | } 195 | AP_free(&q); 196 | return r; 197 | } 198 | T AP_pow(T x, T y, T p) { 199 | T z; 200 | assert(x); 201 | assert(y); 202 | assert(y->sign == 1); 203 | assert(!p || p->sign==1 && !iszero(p) && !isone(p)); 204 | if (iszero(x)) 205 | return AP_new(0); 206 | if (iszero(y)) 207 | return AP_new(1); 208 | if (isone(x)) 209 | return AP_new((((y)->digits[0]&1) == 0) ? 1 : x->sign); 210 | if (p) 211 | if (isone(y)) 212 | z = AP_mod(x, p); 213 | else { 214 | T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, p); 215 | z = mulmod(t, t, p); 216 | AP_free(&y2); 217 | AP_free(&t); 218 | if (!(((y)->digits[0]&1) == 0)) { 219 | z = mulmod(y2 = AP_mod(x, p), t = z, p); 220 | AP_free(&y2); 221 | AP_free(&t); 222 | } 223 | } 224 | else 225 | if (isone(y)) 226 | z = AP_addi(x, 0); 227 | else { 228 | T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, NULL); 229 | z = AP_mul(t, t); 230 | AP_free(&y2); 231 | AP_free(&t); 232 | if (!(((y)->digits[0]&1) == 0)) { 233 | z = AP_mul(x, t = z); 234 | AP_free(&t); 235 | } 236 | } 237 | return z; 238 | } 239 | int AP_cmp(T x, T y) { 240 | assert(x); 241 | assert(y); 242 | if (!((x->sign^y->sign) == 0)) 243 | return x->sign; 244 | else if (x->sign == 1) 245 | return cmp(x, y); 246 | else 247 | return cmp(y, x); 248 | } 249 | T AP_addi(T x, long int y) { 250 | unsigned char d[sizeof (unsigned long)]; 251 | struct T t; 252 | t.size = sizeof d; 253 | t.digits = d; 254 | return AP_add(x, set(&t, y)); 255 | } 256 | T AP_subi(T x, long int y) { 257 | unsigned char d[sizeof (unsigned long)]; 258 | struct T t; 259 | t.size = sizeof d; 260 | t.digits = d; 261 | return AP_sub(x, set(&t, y)); 262 | } 263 | T AP_muli(T x, long int y) { 264 | unsigned char d[sizeof (unsigned long)]; 265 | struct T t; 266 | t.size = sizeof d; 267 | t.digits = d; 268 | return AP_mul(x, set(&t, y)); 269 | } 270 | T AP_divi(T x, long int y) { 271 | unsigned char d[sizeof (unsigned long)]; 272 | struct T t; 273 | t.size = sizeof d; 274 | t.digits = d; 275 | return AP_div(x, set(&t, y)); 276 | } 277 | int AP_cmpi(T x, long int y) { 278 | unsigned char d[sizeof (unsigned long)]; 279 | struct T t; 280 | t.size = sizeof d; 281 | t.digits = d; 282 | return AP_cmp(x, set(&t, y)); 283 | } 284 | long int AP_modi(T x, long int y) { 285 | long int rem; 286 | T r; 287 | unsigned char d[sizeof (unsigned long)]; 288 | struct T t; 289 | t.size = sizeof d; 290 | t.digits = d; 291 | r = AP_mod(x, set(&t, y)); 292 | rem = XP_toint(r->ndigits, r->digits); 293 | AP_free(&r); 294 | return rem; 295 | } 296 | T AP_lshift(T x, int s) { 297 | T z; 298 | assert(x); 299 | assert(s >= 0); 300 | z = mk(x->ndigits + ((s+7)&~7)/8); 301 | XP_lshift(z->size, z->digits, x->ndigits, 302 | x->digits, s, 0); 303 | z->sign = x->sign; 304 | return normalize(z, z->size); 305 | } 306 | T AP_rshift(T x, int s) { 307 | assert(x); 308 | assert(s >= 0); 309 | if (s >= 8*x->ndigits) 310 | return AP_new(0); 311 | else { 312 | T z = mk(x->ndigits - s/8); 313 | XP_rshift(z->size, z->digits, x->ndigits, 314 | x->digits, s, 0); 315 | normalize(z, z->size); 316 | z->sign = iszero(z) ? 1 : x->sign; 317 | return z; 318 | } 319 | } 320 | long int AP_toint(T x) { 321 | unsigned long u; 322 | assert(x); 323 | u = XP_toint(x->ndigits, x->digits)%(LONG_MAX + 1UL); 324 | if (x->sign == -1) 325 | return -(long)u; 326 | else 327 | return (long)u; 328 | } 329 | T AP_fromstr(const char *str, int base, char **end) { 330 | T z; 331 | const char *p = str; 332 | char *endp, sign = '\0'; 333 | int carry; 334 | assert(p); 335 | assert(base >= 2 && base <= 36); 336 | while (*p && isspace(*p)) 337 | p++; 338 | if (*p == '-' || *p == '+') 339 | sign = *p++; 340 | { 341 | const char *start; 342 | int k, n = 0; 343 | for ( ; *p == '0' && p[1] == '0'; p++) 344 | ; 345 | start = p; 346 | for ( ; ( '0' <= *p && *p <= '9' && *p < '0' + base 347 | || 'a' <= *p && *p <= 'z' && *p < 'a' + base - 10 348 | || 'A' <= *p && *p <= 'Z' && *p < 'A' + base - 10); p++) 349 | n++; 350 | for (k = 1; (1<size, z->digits, p, 356 | base, &endp); 357 | assert(carry == 0); 358 | normalize(z, z->size); 359 | if (endp == p) { 360 | endp = (char *)str; 361 | z = AP_new(0); 362 | } else 363 | z->sign = iszero(z) || sign != '-' ? 1 : -1; 364 | if (end) 365 | *end = (char *)endp; 366 | return z; 367 | } 368 | char *AP_tostr(char *str, int size, int base, T x) { 369 | XP_T q; 370 | assert(x); 371 | assert(base >= 2 && base <= 36); 372 | assert(str == NULL || size > 1); 373 | if (str == NULL) { 374 | { 375 | int k; 376 | for (k = 5; (1< base; k--) 377 | ; 378 | size = (8*x->ndigits)/k + 1 + 1; 379 | if (x->sign == -1) 380 | size++; 381 | } 382 | str = ALLOC(size); 383 | } 384 | q = ALLOC(x->ndigits); 385 | memcpy(q, x->digits, x->ndigits); 386 | if (x->sign == -1) { 387 | str[0] = '-'; 388 | XP_tostr(str + 1, size - 1, base, x->ndigits, q); 389 | } else 390 | XP_tostr(str, size, base, x->ndigits, q); 391 | FREE(q); 392 | return str; 393 | } 394 | void AP_fmt(int code, va_list_box *box, 395 | int put(int c, void *cl), void *cl, 396 | unsigned char flags[], int width, int precision) { 397 | T x; 398 | char *buf; 399 | assert(box && flags); 400 | x = va_arg(box->ap, T); 401 | assert(x); 402 | buf = AP_tostr(NULL, 0, 10, x); 403 | Fmt_putd(buf, strlen(buf), put, cl, flags, 404 | width, precision); 405 | FREE(buf); 406 | } 407 | -------------------------------------------------------------------------------- /src/arena.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "except.h" 6 | #include "arena.h" 7 | #define T Arena_T 8 | const Except_T Arena_NewFailed = 9 | { "Arena creation failed" }; 10 | const Except_T Arena_Failed = 11 | { "Arena allocation failed" }; 12 | #define THRESHOLD 10 13 | struct T { 14 | T prev; 15 | char *avail; 16 | char *limit; 17 | }; 18 | union align { 19 | #ifdef MAXALIGN 20 | char pad[MAXALIGN]; 21 | #else 22 | int i; 23 | long l; 24 | long *lp; 25 | void *p; 26 | void (*fp)(void); 27 | float f; 28 | double d; 29 | long double ld; 30 | #endif 31 | }; 32 | union header { 33 | struct T b; 34 | union align a; 35 | }; 36 | static T freechunks; 37 | static int nfree; 38 | T Arena_new(void) { 39 | T arena = malloc(sizeof (*arena)); 40 | if (arena == NULL) 41 | RAISE(Arena_NewFailed); 42 | arena->prev = NULL; 43 | arena->limit = arena->avail = NULL; 44 | return arena; 45 | } 46 | void Arena_dispose(T *ap) { 47 | assert(ap && *ap); 48 | Arena_free(*ap); 49 | free(*ap); 50 | *ap = NULL; 51 | } 52 | void *Arena_alloc(T arena, long nbytes, 53 | const char *file, int line) { 54 | assert(arena); 55 | assert(nbytes > 0); 56 | nbytes = ((nbytes + sizeof (union align) - 1)/ 57 | (sizeof (union align)))*(sizeof (union align)); 58 | while (nbytes > arena->limit - arena->avail) { 59 | T ptr; 60 | char *limit; 61 | if ((ptr = freechunks) != NULL) { 62 | freechunks = freechunks->prev; 63 | nfree--; 64 | limit = ptr->limit; 65 | } else { 66 | long m = sizeof (union header) + nbytes + 10*1024; 67 | ptr = malloc(m); 68 | if (ptr == NULL) 69 | { 70 | if (file == NULL) 71 | RAISE(Arena_Failed); 72 | else 73 | Except_raise(&Arena_Failed, file, line); 74 | } 75 | limit = (char *)ptr + m; 76 | } 77 | *ptr = *arena; 78 | arena->avail = (char *)((union header *)ptr + 1); 79 | arena->limit = limit; 80 | arena->prev = ptr; 81 | } 82 | arena->avail += nbytes; 83 | return arena->avail - nbytes; 84 | } 85 | void *Arena_calloc(T arena, long count, long nbytes, 86 | const char *file, int line) { 87 | void *ptr; 88 | assert(count > 0); 89 | ptr = Arena_alloc(arena, count*nbytes, file, line); 90 | memset(ptr, '\0', count*nbytes); 91 | return ptr; 92 | } 93 | void Arena_free(T arena) { 94 | assert(arena); 95 | while (arena->prev) { 96 | struct T tmp = *arena->prev; 97 | if (nfree < THRESHOLD) { 98 | arena->prev->prev = freechunks; 99 | freechunks = arena->prev; 100 | nfree++; 101 | freechunks->limit = arena->limit; 102 | } else 103 | free(arena->prev); 104 | *arena = tmp; 105 | } 106 | assert(arena->limit == NULL); 107 | assert(arena->avail == NULL); 108 | } 109 | -------------------------------------------------------------------------------- /src/arith.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include "arith.h" 3 | int Arith_max(int x, int y) { 4 | return x > y ? x : y; 5 | } 6 | int Arith_min(int x, int y) { 7 | return x > y ? y : x; 8 | } 9 | int Arith_div(int x, int y) { 10 | if (-13/5 == -2 11 | && (x < 0) != (y < 0) && x%y != 0) 12 | return x/y - 1; 13 | else 14 | return x/y; 15 | } 16 | int Arith_mod(int x, int y) { 17 | if (-13/5 == -2 18 | && (x < 0) != (y < 0) && x%y != 0) 19 | return x%y + y; 20 | else 21 | return x%y; 22 | } 23 | int Arith_floor(int x, int y) { 24 | return Arith_div(x, y); 25 | } 26 | int Arith_ceiling(int x, int y) { 27 | return Arith_div(x, y) + (x%y != 0); 28 | } 29 | -------------------------------------------------------------------------------- /src/array.c: -------------------------------------------------------------------------------- 1 | static const char *rcsid = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "array.h" 6 | #include "arrayrep.h" 7 | #include "mem.h" 8 | #define T Array_T 9 | T Array_new(int length, int size) { 10 | T array; 11 | NEW(array); 12 | if (length > 0) 13 | ArrayRep_init(array, length, size, 14 | CALLOC(length, size)); 15 | else 16 | ArrayRep_init(array, length, size, NULL); 17 | return array; 18 | } 19 | void ArrayRep_init(T array, int length, int size, 20 | void *ary) { 21 | assert(array); 22 | assert(ary && length>0 || length==0 && ary==NULL); 23 | assert(size > 0); 24 | array->length = length; 25 | array->size = size; 26 | if (length > 0) 27 | array->array = ary; 28 | else 29 | array->array = NULL; 30 | } 31 | void Array_free(T *array) { 32 | assert(array && *array); 33 | FREE((*array)->array); 34 | FREE(*array); 35 | } 36 | void *Array_get(T array, int i) { 37 | assert(array); 38 | assert(i >= 0 && i < array->length); 39 | return array->array + i*array->size; 40 | } 41 | void *Array_put(T array, int i, void *elem) { 42 | assert(array); 43 | assert(i >= 0 && i < array->length); 44 | assert(elem); 45 | memcpy(array->array + i*array->size, elem, 46 | array->size); 47 | return elem; 48 | } 49 | int Array_length(T array) { 50 | assert(array); 51 | return array->length; 52 | } 53 | int Array_size(T array) { 54 | assert(array); 55 | return array->size; 56 | } 57 | void Array_resize(T array, int length) { 58 | assert(array); 59 | assert(length >= 0); 60 | if (length == 0) 61 | FREE(array->array); 62 | else if (array->length == 0) 63 | array->array = ALLOC(length*array->size); 64 | else 65 | RESIZE(array->array, length*array->size); 66 | array->length = length; 67 | } 68 | T Array_copy(T array, int length) { 69 | T copy; 70 | assert(array); 71 | assert(length >= 0); 72 | copy = Array_new(length, array->size); 73 | if (copy->length >= array->length 74 | && array->length > 0) 75 | memcpy(copy->array, array->array, 76 | array->length*array->size); 77 | else if (array->length > copy->length 78 | && copy->length > 0) 79 | memcpy(copy->array, array->array, 80 | copy->length*array->size); 81 | return copy; 82 | } 83 | -------------------------------------------------------------------------------- /src/assert.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include "assert.h" 3 | const Except_T Assert_Failed = { "Assertion failed" }; 4 | void (assert)(int e) { 5 | assert(e); 6 | } 7 | -------------------------------------------------------------------------------- /src/atom.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include "atom.h" 3 | #include 4 | #include "assert.h" 5 | #include 6 | #include "mem.h" 7 | #define NELEMS(x) ((sizeof (x))/(sizeof ((x)[0]))) 8 | static struct atom { 9 | struct atom *link; 10 | int len; 11 | char *str; 12 | } *buckets[2048]; 13 | static unsigned long scatter[] = { 14 | 2078917053, 143302914, 1027100827, 1953210302, 755253631, 2002600785, 15 | 1405390230, 45248011, 1099951567, 433832350, 2018585307, 438263339, 16 | 813528929, 1703199216, 618906479, 573714703, 766270699, 275680090, 17 | 1510320440, 1583583926, 1723401032, 1965443329, 1098183682, 1636505764, 18 | 980071615, 1011597961, 643279273, 1315461275, 157584038, 1069844923, 19 | 471560540, 89017443, 1213147837, 1498661368, 2042227746, 1968401469, 20 | 1353778505, 1300134328, 2013649480, 306246424, 1733966678, 1884751139, 21 | 744509763, 400011959, 1440466707, 1363416242, 973726663, 59253759, 22 | 1639096332, 336563455, 1642837685, 1215013716, 154523136, 593537720, 23 | 704035832, 1134594751, 1605135681, 1347315106, 302572379, 1762719719, 24 | 269676381, 774132919, 1851737163, 1482824219, 125310639, 1746481261, 25 | 1303742040, 1479089144, 899131941, 1169907872, 1785335569, 485614972, 26 | 907175364, 382361684, 885626931, 200158423, 1745777927, 1859353594, 27 | 259412182, 1237390611, 48433401, 1902249868, 304920680, 202956538, 28 | 348303940, 1008956512, 1337551289, 1953439621, 208787970, 1640123668, 29 | 1568675693, 478464352, 266772940, 1272929208, 1961288571, 392083579, 30 | 871926821, 1117546963, 1871172724, 1771058762, 139971187, 1509024645, 31 | 109190086, 1047146551, 1891386329, 994817018, 1247304975, 1489680608, 32 | 706686964, 1506717157, 579587572, 755120366, 1261483377, 884508252, 33 | 958076904, 1609787317, 1893464764, 148144545, 1415743291, 2102252735, 34 | 1788268214, 836935336, 433233439, 2055041154, 2109864544, 247038362, 35 | 299641085, 834307717, 1364585325, 23330161, 457882831, 1504556512, 36 | 1532354806, 567072918, 404219416, 1276257488, 1561889936, 1651524391, 37 | 618454448, 121093252, 1010757900, 1198042020, 876213618, 124757630, 38 | 2082550272, 1834290522, 1734544947, 1828531389, 1982435068, 1002804590, 39 | 1783300476, 1623219634, 1839739926, 69050267, 1530777140, 1802120822, 40 | 316088629, 1830418225, 488944891, 1680673954, 1853748387, 946827723, 41 | 1037746818, 1238619545, 1513900641, 1441966234, 367393385, 928306929, 42 | 946006977, 985847834, 1049400181, 1956764878, 36406206, 1925613800, 43 | 2081522508, 2118956479, 1612420674, 1668583807, 1800004220, 1447372094, 44 | 523904750, 1435821048, 923108080, 216161028, 1504871315, 306401572, 45 | 2018281851, 1820959944, 2136819798, 359743094, 1354150250, 1843084537, 46 | 1306570817, 244413420, 934220434, 672987810, 1686379655, 1301613820, 47 | 1601294739, 484902984, 139978006, 503211273, 294184214, 176384212, 48 | 281341425, 228223074, 147857043, 1893762099, 1896806882, 1947861263, 49 | 1193650546, 273227984, 1236198663, 2116758626, 489389012, 593586330, 50 | 275676551, 360187215, 267062626, 265012701, 719930310, 1621212876, 51 | 2108097238, 2026501127, 1865626297, 894834024, 552005290, 1404522304, 52 | 48964196, 5816381, 1889425288, 188942202, 509027654, 36125855, 53 | 365326415, 790369079, 264348929, 513183458, 536647531, 13672163, 54 | 313561074, 1730298077, 286900147, 1549759737, 1699573055, 776289160, 55 | 2143346068, 1975249606, 1136476375, 262925046, 92778659, 1856406685, 56 | 1884137923, 53392249, 1735424165, 1602280572 57 | }; 58 | const char *Atom_string(const char *str) { 59 | assert(str); 60 | return Atom_new(str, strlen(str)); 61 | } 62 | const char *Atom_int(long n) { 63 | char str[43]; 64 | char *s = str + sizeof str; 65 | unsigned long m; 66 | if (n == LONG_MIN) 67 | m = LONG_MAX + 1UL; 68 | else if (n < 0) 69 | m = -n; 70 | else 71 | m = n; 72 | do 73 | *--s = m%10 + '0'; 74 | while ((m /= 10) > 0); 75 | if (n < 0) 76 | *--s = '-'; 77 | return Atom_new(s, (str + sizeof str) - s); 78 | } 79 | const char *Atom_new(const char *str, int len) { 80 | unsigned long h; 81 | int i; 82 | struct atom *p; 83 | assert(str); 84 | assert(len >= 0); 85 | for (h = 0, i = 0; i < len; i++) 86 | h = (h<<1) + scatter[(unsigned char)str[i]]; 87 | h &= NELEMS(buckets)-1; 88 | for (p = buckets[h]; p; p = p->link) 89 | if (len == p->len) { 90 | for (i = 0; i < len && p->str[i] == str[i]; ) 91 | i++; 92 | if (i == len) 93 | return p->str; 94 | } 95 | p = ALLOC(sizeof (*p) + len + 1); 96 | p->len = len; 97 | p->str = (char *)(p + 1); 98 | if (len > 0) 99 | memcpy(p->str, str, len); 100 | p->str[len] = '\0'; 101 | p->link = buckets[h]; 102 | buckets[h] = p; 103 | return p->str; 104 | } 105 | int Atom_length(const char *str) { 106 | struct atom *p; 107 | int i; 108 | assert(str); 109 | for (i = 0; i < NELEMS(buckets); i++) 110 | for (p = buckets[i]; p; p = p->link) 111 | if (p->str == str) 112 | return p->len; 113 | assert(0); 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /src/bit.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "bit.h" 6 | #include "mem.h" 7 | #define T Bit_T 8 | struct T { 9 | int length; 10 | unsigned char *bytes; 11 | unsigned long *words; 12 | }; 13 | #define BPW (8*sizeof (unsigned long)) 14 | #define nwords(len) ((((len) + BPW - 1)&(~(BPW-1)))/BPW) 15 | #define nbytes(len) ((((len) + 8 - 1)&(~(8-1)))/8) 16 | #define setop(sequal, snull, tnull, op) \ 17 | if (s == t) { assert(s); return sequal; } \ 18 | else if (s == NULL) { assert(t); return snull; } \ 19 | else if (t == NULL) return tnull; \ 20 | else { \ 21 | int i; T set; \ 22 | assert(s->length == t->length); \ 23 | set = Bit_new(s->length); \ 24 | for (i = nwords(s->length); --i >= 0; ) \ 25 | set->words[i] = s->words[i] op t->words[i]; \ 26 | return set; } 27 | unsigned char msbmask[] = { 28 | 0xFF, 0xFE, 0xFC, 0xF8, 29 | 0xF0, 0xE0, 0xC0, 0x80 30 | }; 31 | unsigned char lsbmask[] = { 32 | 0x01, 0x03, 0x07, 0x0F, 33 | 0x1F, 0x3F, 0x7F, 0xFF 34 | }; 35 | static T copy(T t) { 36 | T set; 37 | assert(t); 38 | set = Bit_new(t->length); 39 | if (t->length > 0) 40 | memcpy(set->bytes, t->bytes, nbytes(t->length)); 41 | return set; 42 | } 43 | T Bit_new(int length) { 44 | T set; 45 | assert(length >= 0); 46 | NEW(set); 47 | if (length > 0) 48 | set->words = CALLOC(nwords(length), 49 | sizeof (unsigned long)); 50 | else 51 | set->words = NULL; 52 | set->bytes = (unsigned char *)set->words; 53 | set->length = length; 54 | return set; 55 | } 56 | void Bit_free(T *set) { 57 | assert(set && *set); 58 | FREE((*set)->words); 59 | FREE(*set); 60 | } 61 | int Bit_length(T set) { 62 | assert(set); 63 | return set->length; 64 | } 65 | int Bit_count(T set) { 66 | int length = 0, n; 67 | static char count[] = { 68 | 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; 69 | assert(set); 70 | for (n = nbytes(set->length); --n >= 0; ) { 71 | unsigned char c = set->bytes[n]; 72 | length += count[c&0xF] + count[c>>4]; 73 | } 74 | return length; 75 | } 76 | int Bit_get(T set, int n) { 77 | assert(set); 78 | assert(0 <= n && n < set->length); 79 | return ((set->bytes[n/8]>>(n%8))&1); 80 | } 81 | int Bit_put(T set, int n, int bit) { 82 | int prev; 83 | assert(set); 84 | assert(bit == 0 || bit == 1); 85 | assert(0 <= n && n < set->length); 86 | prev = ((set->bytes[n/8]>>(n%8))&1); 87 | if (bit == 1) 88 | set->bytes[n/8] |= 1<<(n%8); 89 | else 90 | set->bytes[n/8] &= ~(1<<(n%8)); 91 | return prev; 92 | } 93 | void Bit_set(T set, int lo, int hi) { 94 | assert(set); 95 | assert(0 <= lo && hi < set->length); 96 | assert(lo <= hi); 97 | if (lo/8 < hi/8) { 98 | set->bytes[lo/8] |= msbmask[lo%8]; 99 | { 100 | int i; 101 | for (i = lo/8+1; i < hi/8; i++) 102 | set->bytes[i] = 0xFF; 103 | } 104 | set->bytes[hi/8] |= lsbmask[hi%8]; 105 | } else 106 | set->bytes[lo/8] |= (msbmask[lo%8]&lsbmask[hi%8]); 107 | } 108 | void Bit_clear(T set, int lo, int hi) { 109 | assert(set); 110 | assert(0 <= lo && hi < set->length); 111 | assert(lo <= hi); 112 | if (lo/8 < hi/8) { 113 | int i; 114 | set->bytes[lo/8] &= ~msbmask[lo%8]; 115 | for (i = lo/8+1; i < hi/8; i++) 116 | set->bytes[i] = 0; 117 | set->bytes[hi/8] &= ~lsbmask[hi%8]; 118 | } else 119 | set->bytes[lo/8] &= ~(msbmask[lo%8]&lsbmask[hi%8]); 120 | } 121 | void Bit_not(T set, int lo, int hi) { 122 | assert(set); 123 | assert(0 <= lo && hi < set->length); 124 | assert(lo <= hi); 125 | if (lo/8 < hi/8) { 126 | int i; 127 | set->bytes[lo/8] ^= msbmask[lo%8]; 128 | for (i = lo/8+1; i < hi/8; i++) 129 | set->bytes[i] ^= 0xFF; 130 | set->bytes[hi/8] ^= lsbmask[hi%8]; 131 | } else 132 | set->bytes[lo/8] ^= (msbmask[lo%8]&lsbmask[hi%8]); 133 | } 134 | void Bit_map(T set, 135 | void apply(int n, int bit, void *cl), void *cl) { 136 | int n; 137 | assert(set); 138 | for (n = 0; n < set->length; n++) 139 | apply(n, ((set->bytes[n/8]>>(n%8))&1), cl); 140 | } 141 | int Bit_eq(T s, T t) { 142 | int i; 143 | assert(s && t); 144 | assert(s->length == t->length); 145 | for (i = nwords(s->length); --i >= 0; ) 146 | if (s->words[i] != t->words[i]) 147 | return 0; 148 | return 1; 149 | } 150 | int Bit_leq(T s, T t) { 151 | int i; 152 | assert(s && t); 153 | assert(s->length == t->length); 154 | for (i = nwords(s->length); --i >= 0; ) 155 | if ((s->words[i]&~t->words[i]) != 0) 156 | return 0; 157 | return 1; 158 | } 159 | int Bit_lt(T s, T t) { 160 | int i, lt = 0; 161 | assert(s && t); 162 | assert(s->length == t->length); 163 | for (i = nwords(s->length); --i >= 0; ) 164 | if ((s->words[i]&~t->words[i]) != 0) 165 | return 0; 166 | else if (s->words[i] != t->words[i]) 167 | lt |= 1; 168 | return lt; 169 | } 170 | T Bit_union(T s, T t) { 171 | setop(copy(t), copy(t), copy(s), |) 172 | } 173 | T Bit_inter(T s, T t) { 174 | setop(copy(t), 175 | Bit_new(t->length), Bit_new(s->length), &) 176 | } 177 | T Bit_minus(T s, T t) { 178 | setop(Bit_new(s->length), 179 | Bit_new(t->length), copy(s), & ~) 180 | } 181 | T Bit_diff(T s, T t) { 182 | setop(Bit_new(s->length), copy(t), copy(s), ^) 183 | } 184 | -------------------------------------------------------------------------------- /src/chan.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include "assert.h" 4 | #include "mem.h" 5 | #include "chan.h" 6 | #include "sem.h" 7 | #define T Chan_T 8 | struct T { 9 | const void *ptr; 10 | int *size; 11 | Sem_T send, recv, sync; 12 | }; 13 | T Chan_new(void) { 14 | T c; 15 | NEW(c); 16 | Sem_init(&c->send, 1); 17 | Sem_init(&c->recv, 0); 18 | Sem_init(&c->sync, 0); 19 | return c; 20 | } 21 | int Chan_send(Chan_T c, const void *ptr, int size) { 22 | assert(c); 23 | assert(ptr); 24 | assert(size >= 0); 25 | Sem_wait(&c->send); 26 | c->ptr = ptr; 27 | c->size = &size; 28 | Sem_signal(&c->recv); 29 | Sem_wait(&c->sync); 30 | return size; 31 | } 32 | int Chan_receive(Chan_T c, void *ptr, int size) { 33 | int n; 34 | assert(c); 35 | assert(ptr); 36 | assert(size >= 0); 37 | Sem_wait(&c->recv); 38 | n = *c->size; 39 | if (size < n) 40 | n = size; 41 | *c->size = n; 42 | if (n > 0) 43 | memcpy(ptr, c->ptr, n); 44 | Sem_signal(&c->sync); 45 | Sem_signal(&c->send); 46 | return n; 47 | } 48 | -------------------------------------------------------------------------------- /src/except.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$" "\n$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "except.h" 6 | #define T Except_T 7 | Except_Frame *Except_stack = NULL; 8 | void Except_raise(const T *e, const char *file, 9 | int line) { 10 | #ifdef WIN32 11 | Except_Frame *p; 12 | 13 | if (Except_index == -1) 14 | Except_init(); 15 | p = TlsGetValue(Except_index); 16 | #else 17 | Except_Frame *p = Except_stack; 18 | #endif 19 | assert(e); 20 | if (p == NULL) { 21 | fprintf(stderr, "Uncaught exception"); 22 | if (e->reason) 23 | fprintf(stderr, " %s", e->reason); 24 | else 25 | fprintf(stderr, " at 0x%p", e); 26 | if (file && line > 0) 27 | fprintf(stderr, " raised at %s:%d\n", file, line); 28 | fprintf(stderr, "aborting...\n"); 29 | fflush(stderr); 30 | abort(); 31 | } 32 | p->exception = e; 33 | p->file = file; 34 | p->line = line; 35 | #ifdef WIN32 36 | Except_pop(); 37 | #else 38 | Except_stack = Except_stack->prev; 39 | #endif 40 | longjmp(p->env, Except_raised); 41 | } 42 | #ifdef WIN32 43 | _CRTIMP void __cdecl _assert(void *, void *, unsigned); 44 | #undef assert 45 | #define assert(e) ((e) || (_assert(#e, __FILE__, __LINE__), 0)) 46 | 47 | int Except_index = -1; 48 | void Except_init(void) { 49 | BOOL cond; 50 | 51 | Except_index = TlsAlloc(); 52 | assert(Except_index != TLS_OUT_OF_INDEXES); 53 | cond = TlsSetValue(Except_index, NULL); 54 | assert(cond == TRUE); 55 | } 56 | 57 | void Except_push(Except_Frame *fp) { 58 | BOOL cond; 59 | 60 | fp->prev = TlsGetValue(Except_index); 61 | cond = TlsSetValue(Except_index, fp); 62 | assert(cond == TRUE); 63 | } 64 | 65 | void Except_pop(void) { 66 | BOOL cond; 67 | Except_Frame *tos = TlsGetValue(Except_index); 68 | 69 | cond = TlsSetValue(Except_index, tos->prev); 70 | assert(cond == TRUE); 71 | } 72 | #endif 73 | -------------------------------------------------------------------------------- /src/fmt.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "assert.h" 11 | #include "except.h" 12 | #include "fmt.h" 13 | #include "mem.h" 14 | #define T Fmt_T 15 | struct buf { 16 | char *buf; 17 | char *bp; 18 | int size; 19 | }; 20 | #define pad(n,c) do { int nn = (n); \ 21 | while (nn-- > 0) \ 22 | put((c), cl); } while (0) 23 | static void cvt_s(int code, va_list_box *box, 24 | int put(int c, void *cl), void *cl, 25 | unsigned char flags[], int width, int precision) { 26 | char *str = va_arg(box->ap, char *); 27 | assert(str); 28 | Fmt_puts(str, strlen(str), put, cl, flags, 29 | width, precision); 30 | } 31 | static void cvt_d(int code, va_list_box *box, 32 | int put(int c, void *cl), void *cl, 33 | unsigned char flags[], int width, int precision) { 34 | int val = va_arg(box->ap, int); 35 | unsigned m; 36 | char buf[43]; 37 | char *p = buf + sizeof buf; 38 | if (val == INT_MIN) 39 | m = INT_MAX + 1U; 40 | else if (val < 0) 41 | m = -val; 42 | else 43 | m = val; 44 | do 45 | *--p = m%10 + '0'; 46 | while ((m /= 10) > 0); 47 | if (val < 0) 48 | *--p = '-'; 49 | Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, 50 | width, precision); 51 | } 52 | static void cvt_u(int code, va_list_box *box, 53 | int put(int c, void *cl), void *cl, 54 | unsigned char flags[], int width, int precision) { 55 | unsigned m = va_arg(box->ap, unsigned); 56 | char buf[43]; 57 | char *p = buf + sizeof buf; 58 | do 59 | *--p = m%10 + '0'; 60 | while ((m /= 10) > 0); 61 | Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, 62 | width, precision); 63 | } 64 | static void cvt_o(int code, va_list_box *box, 65 | int put(int c, void *cl), void *cl, 66 | unsigned char flags[], int width, int precision) { 67 | unsigned m = va_arg(box->ap, unsigned); 68 | char buf[43]; 69 | char *p = buf + sizeof buf; 70 | do 71 | *--p = (m&0x7) + '0'; 72 | while ((m>>= 3) != 0); 73 | Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, 74 | width, precision); 75 | } 76 | static void cvt_x(int code, va_list_box *box, 77 | int put(int c, void *cl), void *cl, 78 | unsigned char flags[], int width, int precision) { 79 | unsigned m = va_arg(box->ap, unsigned); 80 | char buf[43]; 81 | char *p = buf + sizeof buf; 82 | do 83 | *--p = "0123456789abcdef"[m&0xf]; 84 | while ((m>>= 4) != 0); 85 | Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, 86 | width, precision); 87 | } 88 | static void cvt_p(int code, va_list_box *box, 89 | int put(int c, void *cl), void *cl, 90 | unsigned char flags[], int width, int precision) { 91 | unsigned long m = (unsigned long)va_arg(box->ap, void*); 92 | char buf[43]; 93 | char *p = buf + sizeof buf; 94 | precision = INT_MIN; 95 | do 96 | *--p = "0123456789abcdef"[m&0xf]; 97 | while ((m>>= 4) != 0); 98 | Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags, 99 | width, precision); 100 | } 101 | static void cvt_c(int code, va_list_box *box, 102 | int put(int c, void *cl), void *cl, 103 | unsigned char flags[], int width, int precision) { 104 | if (width == INT_MIN) 105 | width = 0; 106 | if (width < 0) { 107 | flags['-'] = 1; 108 | width = -width; 109 | } 110 | if (!flags['-']) 111 | pad(width - 1, ' '); 112 | put((unsigned char)va_arg(box->ap, int), cl); 113 | if ( flags['-']) 114 | pad(width - 1, ' '); 115 | } 116 | static void cvt_f(int code, va_list_box *box, 117 | int put(int c, void *cl), void *cl, 118 | unsigned char flags[], int width, int precision) { 119 | char buf[DBL_MAX_10_EXP+1+1+99+1]; 120 | if (precision < 0) 121 | precision = 6; 122 | if (code == 'g' && precision == 0) 123 | precision = 1; 124 | { 125 | static char fmt[] = "%.dd?"; 126 | assert(precision <= 99); 127 | fmt[4] = code; 128 | fmt[3] = precision%10 + '0'; 129 | fmt[2] = (precision/10)%10 + '0'; 130 | sprintf(buf, fmt, va_arg(box->ap, double)); 131 | } 132 | Fmt_putd(buf, strlen(buf), put, cl, flags, 133 | width, precision); 134 | } 135 | const Except_T Fmt_Overflow = { "Formatting Overflow" }; 136 | static T cvt[256] = { 137 | /* 0- 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 138 | /* 8- 15 */ 0, 0, 0, 0, 0, 0, 0, 0, 139 | /* 16- 23 */ 0, 0, 0, 0, 0, 0, 0, 0, 140 | /* 24- 31 */ 0, 0, 0, 0, 0, 0, 0, 0, 141 | /* 32- 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 142 | /* 40- 47 */ 0, 0, 0, 0, 0, 0, 0, 0, 143 | /* 48- 55 */ 0, 0, 0, 0, 0, 0, 0, 0, 144 | /* 56- 63 */ 0, 0, 0, 0, 0, 0, 0, 0, 145 | /* 64- 71 */ 0, 0, 0, 0, 0, 0, 0, 0, 146 | /* 72- 79 */ 0, 0, 0, 0, 0, 0, 0, 0, 147 | /* 80- 87 */ 0, 0, 0, 0, 0, 0, 0, 0, 148 | /* 88- 95 */ 0, 0, 0, 0, 0, 0, 0, 0, 149 | /* 96-103 */ 0, 0, 0, cvt_c, cvt_d, cvt_f, cvt_f, cvt_f, 150 | /* 104-111 */ 0, 0, 0, 0, 0, 0, 0, cvt_o, 151 | /* 112-119 */ cvt_p, 0, 0, cvt_s, 0, cvt_u, 0, 0, 152 | /* 120-127 */ cvt_x, 0, 0, 0, 0, 0, 0, 0 153 | }; 154 | char *Fmt_flags = "-+ 0"; 155 | static int outc(int c, void *cl) { 156 | FILE *f = cl; 157 | return putc(c, f); 158 | } 159 | static int insert(int c, void *cl) { 160 | struct buf *p = cl; 161 | if (p->bp >= p->buf + p->size) 162 | RAISE(Fmt_Overflow); 163 | *p->bp++ = c; 164 | return c; 165 | } 166 | static int append(int c, void *cl) { 167 | struct buf *p = cl; 168 | if (p->bp >= p->buf + p->size) { 169 | RESIZE(p->buf, 2*p->size); 170 | p->bp = p->buf + p->size; 171 | p->size *= 2; 172 | } 173 | *p->bp++ = c; 174 | return c; 175 | } 176 | void Fmt_puts(const char *str, int len, 177 | int put(int c, void *cl), void *cl, 178 | unsigned char flags[], int width, int precision) { 179 | assert(str); 180 | assert(len >= 0); 181 | assert(flags); 182 | if (width == INT_MIN) 183 | width = 0; 184 | if (width < 0) { 185 | flags['-'] = 1; 186 | width = -width; 187 | } 188 | if (precision >= 0) 189 | flags['0'] = 0; 190 | if (precision >= 0 && precision < len) 191 | len = precision; 192 | if (!flags['-']) 193 | pad(width - len, ' '); 194 | { 195 | int i; 196 | for (i = 0; i < len; i++) 197 | put((unsigned char)*str++, cl); 198 | } 199 | if ( flags['-']) 200 | pad(width - len, ' '); 201 | } 202 | void Fmt_fmt(int put(int c, void *), void *cl, 203 | const char *fmt, ...) { 204 | va_list_box box; 205 | va_start(box.ap, fmt); 206 | Fmt_vfmt(put, cl, fmt, &box); 207 | va_end(box.ap); 208 | } 209 | void Fmt_print(const char *fmt, ...) { 210 | va_list_box box; 211 | va_start(box.ap, fmt); 212 | Fmt_vfmt(outc, stdout, fmt, &box); 213 | va_end(box.ap); 214 | } 215 | void Fmt_fprint(FILE *stream, const char *fmt, ...) { 216 | va_list_box box; 217 | va_start(box.ap, fmt); 218 | Fmt_vfmt(outc, stream, fmt, &box); 219 | va_end(box.ap); 220 | } 221 | int Fmt_sfmt(char *buf, int size, const char *fmt, ...) { 222 | int len; 223 | va_list_box box; 224 | va_start(box.ap, fmt); 225 | len = Fmt_vsfmt(buf, size, fmt, &box); 226 | va_end(box.ap); 227 | return len; 228 | } 229 | int Fmt_vsfmt(char *buf, int size, const char *fmt, 230 | va_list_box *box) { 231 | struct buf cl; 232 | assert(buf); 233 | assert(size > 0); 234 | assert(fmt); 235 | cl.buf = cl.bp = buf; 236 | cl.size = size; 237 | Fmt_vfmt(insert, &cl, fmt, box); 238 | insert(0, &cl); 239 | return cl.bp - cl.buf - 1; 240 | } 241 | char *Fmt_string(const char *fmt, ...) { 242 | char *str; 243 | va_list_box box; 244 | assert(fmt); 245 | va_start(box.ap, fmt); 246 | str = Fmt_vstring(fmt, &box); 247 | va_end(box.ap); 248 | return str; 249 | } 250 | char *Fmt_vstring(const char *fmt, va_list_box *box) { 251 | struct buf cl; 252 | assert(fmt); 253 | cl.size = 256; 254 | cl.buf = cl.bp = ALLOC(cl.size); 255 | Fmt_vfmt(append, &cl, fmt, box); 256 | append(0, &cl); 257 | return RESIZE(cl.buf, cl.bp - cl.buf); 258 | } 259 | void Fmt_vfmt(int put(int c, void *cl), void *cl, 260 | const char *fmt, va_list_box *box) { 261 | assert(put); 262 | assert(fmt); 263 | while (*fmt) 264 | if (*fmt != '%' || *++fmt == '%') 265 | put((unsigned char)*fmt++, cl); 266 | else 267 | { 268 | unsigned char c, flags[256]; 269 | int width = INT_MIN, precision = INT_MIN; 270 | memset(flags, '\0', sizeof flags); 271 | if (Fmt_flags) { 272 | unsigned char c = *fmt; 273 | for ( ; c && strchr(Fmt_flags, c); c = *++fmt) { 274 | assert(flags[c] < 255); 275 | flags[c]++; 276 | } 277 | } 278 | if (*fmt == '*' || isdigit(*fmt)) { 279 | int n; 280 | if (*fmt == '*') { 281 | n = va_arg(box->ap, int); 282 | assert(n != INT_MIN); 283 | fmt++; 284 | } else 285 | for (n = 0; isdigit(*fmt); fmt++) { 286 | int d = *fmt - '0'; 287 | assert(n <= (INT_MAX - d)/10); 288 | n = 10*n + d; 289 | } 290 | width = n; 291 | } 292 | if (*fmt == '.' && (*++fmt == '*' || isdigit(*fmt))) { 293 | int n; 294 | if (*fmt == '*') { 295 | n = va_arg(box->ap, int); 296 | assert(n != INT_MIN); 297 | fmt++; 298 | } else 299 | for (n = 0; isdigit(*fmt); fmt++) { 300 | int d = *fmt - '0'; 301 | assert(n <= (INT_MAX - d)/10); 302 | n = 10*n + d; 303 | } 304 | precision = n; 305 | } 306 | c = *fmt++; 307 | assert(cvt[c]); 308 | (*cvt[c])(c, box, put, cl, flags, width, precision); 309 | } 310 | } 311 | T Fmt_register(int code, T newcvt) { 312 | T old; 313 | assert(0 < code 314 | && code < (int)(sizeof (cvt)/sizeof (cvt[0]))); 315 | old = cvt[code]; 316 | cvt[code] = newcvt; 317 | return old; 318 | } 319 | void Fmt_putd(const char *str, int len, 320 | int put(int c, void *cl), void *cl, 321 | unsigned char flags[], int width, int precision) { 322 | int sign; 323 | assert(str); 324 | assert(len >= 0); 325 | assert(flags); 326 | if (width == INT_MIN) 327 | width = 0; 328 | if (width < 0) { 329 | flags['-'] = 1; 330 | width = -width; 331 | } 332 | if (precision >= 0) 333 | flags['0'] = 0; 334 | if (len > 0 && (*str == '-' || *str == '+')) { 335 | sign = *str++; 336 | len--; 337 | } else if (flags['+']) 338 | sign = '+'; 339 | else if (flags[' ']) 340 | sign = ' '; 341 | else 342 | sign = 0; 343 | { int n; 344 | if (precision < 0) 345 | precision = 1; 346 | if (len < precision) 347 | n = precision; 348 | else if (precision == 0 && len == 1 && str[0] == '0') 349 | n = 0; 350 | else 351 | n = len; 352 | if (sign) 353 | n++; 354 | if (flags['-']) { 355 | if (sign) 356 | put(sign, cl); 357 | } else if (flags['0']) { 358 | if (sign) 359 | put(sign, cl); 360 | pad(width - n, '0'); 361 | } else { 362 | pad(width - n, ' '); 363 | if (sign) 364 | put(sign, cl); 365 | } 366 | pad(precision - len, '0'); 367 | { 368 | int i; 369 | for (i = 0; i < len; i++) 370 | put((unsigned char)*str++, cl); 371 | } 372 | if (flags['-']) 373 | pad(width - n, ' '); } 374 | } 375 | -------------------------------------------------------------------------------- /src/libcii.def: -------------------------------------------------------------------------------- 1 | ; $Id$ 2 | LIBRARY libcii 3 | DESCRIPTION "C Interfaces and Implementations 1.0" 4 | EXPORTS 5 | AP_new 6 | AP_fromstr 7 | AP_toint 8 | AP_tostr 9 | AP_fmt 10 | AP_free 11 | AP_neg 12 | AP_add 13 | AP_sub 14 | AP_mul 15 | AP_div 16 | AP_mod 17 | AP_pow 18 | AP_addi 19 | AP_subi 20 | AP_muli 21 | AP_divi 22 | AP_modi 23 | AP_lshift 24 | AP_rshift 25 | AP_cmp 26 | AP_cmpi 27 | Arena_NewFailed 28 | Arena_Failed 29 | Arena_new 30 | Arena_dispose 31 | Arena_alloc 32 | Arena_calloc 33 | Arena_free 34 | Arith_max 35 | Arith_min 36 | Arith_div 37 | Arith_mod 38 | Arith_ceiling 39 | Arith_floor 40 | Array_new 41 | Array_free 42 | Array_length 43 | Array_size 44 | Array_get 45 | Array_put 46 | Array_resize 47 | Array_copy 48 | ArrayRep_init 49 | Atom_length 50 | Atom_new 51 | Atom_string 52 | Atom_int 53 | Bit_new 54 | Bit_length 55 | Bit_count 56 | Bit_free 57 | Bit_get 58 | Bit_put 59 | Bit_clear 60 | Bit_set 61 | Bit_not 62 | Bit_lt 63 | Bit_eq 64 | Bit_leq 65 | Bit_map 66 | Bit_union 67 | Bit_inter 68 | Bit_minus 69 | Bit_diff 70 | Chan_new 71 | Chan_send 72 | Chan_receive 73 | Except_stack 74 | Except_raise 75 | Assert_Failed 76 | Fmt_flags 77 | Fmt_Overflow 78 | Fmt_fmt 79 | Fmt_vfmt 80 | Fmt_print 81 | Fmt_fprint 82 | Fmt_sfmt 83 | Fmt_vsfmt 84 | Fmt_string 85 | Fmt_vstring 86 | Fmt_register 87 | Fmt_putd 88 | Fmt_puts 89 | List_append 90 | List_copy 91 | List_list 92 | List_pop 93 | List_push 94 | List_reverse 95 | List_length 96 | List_free 97 | List_map 98 | List_toArray 99 | Mem_Failed 100 | Mem_alloc 101 | Mem_calloc 102 | Mem_free 103 | Mem_resize 104 | MP_Overflow 105 | MP_Dividebyzero 106 | MP_set 107 | MP_new 108 | MP_fromint 109 | MP_fromintu 110 | MP_tointu 111 | MP_toint 112 | MP_cvt 113 | MP_cvtu 114 | MP_add 115 | MP_sub 116 | MP_mul 117 | MP_div 118 | MP_mod 119 | MP_neg 120 | MP_addu 121 | MP_subu 122 | MP_mulu 123 | MP_divu 124 | MP_modu 125 | MP_mul2u 126 | MP_mul2 127 | MP_addi 128 | MP_subi 129 | MP_muli 130 | MP_divi 131 | MP_addui 132 | MP_subui 133 | MP_mului 134 | MP_divui 135 | MP_modi 136 | MP_modui 137 | MP_cmp 138 | MP_cmpi 139 | MP_cmpu 140 | MP_cmpui 141 | MP_and 142 | MP_or 143 | MP_xor 144 | MP_not 145 | MP_andi 146 | MP_ori 147 | MP_xori 148 | MP_lshift 149 | MP_rshift 150 | MP_ashift 151 | MP_fromstr 152 | MP_tostr 153 | MP_fmt 154 | MP_fmtu 155 | Ring_new 156 | Ring_ring 157 | Ring_free 158 | Ring_length 159 | Ring_get 160 | Ring_put 161 | Ring_add 162 | Ring_addlo 163 | Ring_addhi 164 | Ring_remove 165 | Ring_remlo 166 | Ring_remhi 167 | Ring_rotate 168 | Sem_init 169 | Sem_new 170 | Sem_wait 171 | Sem_signal 172 | Seq_new 173 | Seq_seq 174 | Seq_free 175 | Seq_length 176 | Seq_get 177 | Seq_put 178 | Seq_addlo 179 | Seq_addhi 180 | Seq_remlo 181 | Seq_remhi 182 | Set_new 183 | Set_free 184 | Set_length 185 | Set_member 186 | Set_put 187 | Set_remove 188 | Set_map 189 | Set_toArray 190 | Set_union 191 | Set_inter 192 | Set_minus 193 | Set_diff 194 | Stack_new 195 | Stack_empty 196 | Stack_push 197 | Stack_pop 198 | Stack_free 199 | Str_sub 200 | Str_dup 201 | Str_cat 202 | Str_catv 203 | Str_reverse 204 | Str_map 205 | Str_pos 206 | Str_len 207 | Str_cmp 208 | Str_chr 209 | Str_rchr 210 | Str_upto 211 | Str_rupto 212 | Str_find 213 | Str_rfind 214 | Str_any 215 | Str_many 216 | Str_rmany 217 | Str_match 218 | Str_rmatch 219 | Str_fmt 220 | Table_new 221 | Table_free 222 | Table_length 223 | Table_put 224 | Table_get 225 | Table_remove 226 | Table_map 227 | Table_toArray 228 | Text_cset 229 | Text_ascii 230 | Text_ucase 231 | Text_lcase 232 | Text_digits 233 | Text_null 234 | Text_put 235 | Text_get 236 | Text_box 237 | Text_sub 238 | Text_pos 239 | Text_cat 240 | Text_dup 241 | Text_reverse 242 | Text_map 243 | Text_cmp 244 | Text_chr 245 | Text_rchr 246 | Text_upto 247 | Text_rupto 248 | Text_any 249 | Text_many 250 | Text_rmany 251 | Text_find 252 | Text_rfind 253 | Text_match 254 | Text_rmatch 255 | Text_fmt 256 | Text_save 257 | Text_restore 258 | Thread_Failed 259 | Thread_Alerted 260 | Thread_init 261 | Thread_new 262 | Thread_exit 263 | Thread_alert 264 | Thread_self 265 | Thread_join 266 | Thread_pause 267 | XP_add 268 | XP_sub 269 | XP_mul 270 | XP_div 271 | XP_sum 272 | XP_diff 273 | XP_product 274 | XP_quotient 275 | XP_neg 276 | XP_cmp 277 | XP_lshift 278 | XP_rshift 279 | XP_length 280 | XP_fromint 281 | XP_toint 282 | XP_fromstr 283 | XP_tostr 284 | Except_init 285 | Except_index 286 | Except_push 287 | Except_pop 288 | -------------------------------------------------------------------------------- /src/list.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "mem.h" 6 | #include "list.h" 7 | #define T List_T 8 | T List_push(T list, void *x) { 9 | T p; 10 | NEW(p); 11 | p->first = x; 12 | p->rest = list; 13 | return p; 14 | } 15 | T List_list(void *x, ...) { 16 | va_list ap; 17 | T list, *p = &list; 18 | va_start(ap, x); 19 | for ( ; x; x = va_arg(ap, void *)) { 20 | NEW(*p); 21 | (*p)->first = x; 22 | p = &(*p)->rest; 23 | } 24 | *p = NULL; 25 | va_end(ap); 26 | return list; 27 | } 28 | T List_append(T list, T tail) { 29 | T *p = &list; 30 | while (*p) 31 | p = &(*p)->rest; 32 | *p = tail; 33 | return list; 34 | } 35 | T List_copy(T list) { 36 | T head, *p = &head; 37 | for ( ; list; list = list->rest) { 38 | NEW(*p); 39 | (*p)->first = list->first; 40 | p = &(*p)->rest; 41 | } 42 | *p = NULL; 43 | return head; 44 | } 45 | T List_pop(T list, void **x) { 46 | if (list) { 47 | T head = list->rest; 48 | if (x) 49 | *x = list->first; 50 | FREE(list); 51 | return head; 52 | } else 53 | return list; 54 | } 55 | T List_reverse(T list) { 56 | T head = NULL, next; 57 | for ( ; list; list = next) { 58 | next = list->rest; 59 | list->rest = head; 60 | head = list; 61 | } 62 | return head; 63 | } 64 | int List_length(T list) { 65 | int n; 66 | for (n = 0; list; list = list->rest) 67 | n++; 68 | return n; 69 | } 70 | void List_free(T *list) { 71 | T next; 72 | assert(list); 73 | for ( ; *list; *list = next) { 74 | next = (*list)->rest; 75 | FREE(*list); 76 | } 77 | } 78 | void List_map(T list, 79 | void apply(void **x, void *cl), void *cl) { 80 | assert(apply); 81 | for ( ; list; list = list->rest) 82 | apply(&list->first, cl); 83 | } 84 | void **List_toArray(T list, void *end) { 85 | int i, n = List_length(list); 86 | void **array = ALLOC((n + 1)*sizeof (*array)); 87 | for (i = 0; i < n; i++) { 88 | array[i] = list->first; 89 | list = list->rest; 90 | } 91 | array[i] = end; 92 | return array; 93 | } 94 | -------------------------------------------------------------------------------- /src/mem.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "except.h" 6 | #include "mem.h" 7 | const Except_T Mem_Failed = { "Allocation failed" }; 8 | void *Mem_alloc(long nbytes, const char *file, int line){ 9 | void *ptr; 10 | assert(nbytes > 0); 11 | ptr = malloc(nbytes); 12 | if (ptr == NULL) 13 | { 14 | if (file == NULL) 15 | RAISE(Mem_Failed); 16 | else 17 | Except_raise(&Mem_Failed, file, line); 18 | } 19 | return ptr; 20 | } 21 | void *Mem_calloc(long count, long nbytes, 22 | const char *file, int line) { 23 | void *ptr; 24 | assert(count > 0); 25 | assert(nbytes > 0); 26 | ptr = calloc(count, nbytes); 27 | if (ptr == NULL) 28 | { 29 | if (file == NULL) 30 | RAISE(Mem_Failed); 31 | else 32 | Except_raise(&Mem_Failed, file, line); 33 | } 34 | return ptr; 35 | } 36 | void Mem_free(void *ptr, const char *file, int line) { 37 | if (ptr) 38 | free(ptr); 39 | } 40 | void *Mem_resize(void *ptr, long nbytes, 41 | const char *file, int line) { 42 | assert(ptr); 43 | assert(nbytes > 0); 44 | ptr = realloc(ptr, nbytes); 45 | if (ptr == NULL) 46 | { 47 | if (file == NULL) 48 | RAISE(Mem_Failed); 49 | else 50 | Except_raise(&Mem_Failed, file, line); 51 | } 52 | return ptr; 53 | } 54 | -------------------------------------------------------------------------------- /src/memchk.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "except.h" 6 | #include "mem.h" 7 | union align { 8 | #ifdef MAXALIGN 9 | char pad[MAXALIGN]; 10 | #else 11 | int i; 12 | long l; 13 | long *lp; 14 | void *p; 15 | void (*fp)(void); 16 | float f; 17 | double d; 18 | long double ld; 19 | #endif 20 | }; 21 | #define hash(p, t) (((unsigned long)(p)>>3) & \ 22 | (sizeof (t)/sizeof ((t)[0])-1)) 23 | #define NDESCRIPTORS 512 24 | #define NALLOC ((4096 + sizeof (union align) - 1)/ \ 25 | (sizeof (union align)))*(sizeof (union align)) 26 | const Except_T Mem_Failed = { "Allocation failed" }; 27 | static struct descriptor { 28 | struct descriptor *free; 29 | struct descriptor *link; 30 | const void *ptr; 31 | long size; 32 | const char *file; 33 | int line; 34 | } *htab[2048]; 35 | static struct descriptor freelist = { &freelist }; 36 | static struct descriptor *find(const void *ptr) { 37 | struct descriptor *bp = htab[hash(ptr, htab)]; 38 | while (bp && bp->ptr != ptr) 39 | bp = bp->link; 40 | return bp; 41 | } 42 | void Mem_free(void *ptr, const char *file, int line) { 43 | if (ptr) { 44 | struct descriptor *bp; 45 | if (((unsigned long)ptr)%(sizeof (union align)) != 0 46 | || (bp = find(ptr)) == NULL || bp->free) 47 | Except_raise(&Assert_Failed, file, line); 48 | bp->free = freelist.free; 49 | freelist.free = bp; 50 | } 51 | } 52 | void *Mem_resize(void *ptr, long nbytes, 53 | const char *file, int line) { 54 | struct descriptor *bp; 55 | void *newptr; 56 | assert(ptr); 57 | assert(nbytes > 0); 58 | if (((unsigned long)ptr)%(sizeof (union align)) != 0 59 | || (bp = find(ptr)) == NULL || bp->free) 60 | Except_raise(&Assert_Failed, file, line); 61 | newptr = Mem_alloc(nbytes, file, line); 62 | memcpy(newptr, ptr, 63 | nbytes < bp->size ? nbytes : bp->size); 64 | Mem_free(ptr, file, line); 65 | return newptr; 66 | } 67 | void *Mem_calloc(long count, long nbytes, 68 | const char *file, int line) { 69 | void *ptr; 70 | assert(count > 0); 71 | assert(nbytes > 0); 72 | ptr = Mem_alloc(count*nbytes, file, line); 73 | memset(ptr, '\0', count*nbytes); 74 | return ptr; 75 | } 76 | static struct descriptor *dalloc(void *ptr, long size, 77 | const char *file, int line) { 78 | static struct descriptor *avail; 79 | static int nleft; 80 | if (nleft <= 0) { 81 | avail = malloc(NDESCRIPTORS*sizeof (*avail)); 82 | if (avail == NULL) 83 | return NULL; 84 | nleft = NDESCRIPTORS; 85 | } 86 | avail->ptr = ptr; 87 | avail->size = size; 88 | avail->file = file; 89 | avail->line = line; 90 | avail->free = avail->link = NULL; 91 | nleft--; 92 | return avail++; 93 | } 94 | void *Mem_alloc(long nbytes, const char *file, int line){ 95 | struct descriptor *bp; 96 | void *ptr; 97 | assert(nbytes > 0); 98 | nbytes = ((nbytes + sizeof (union align) - 1)/ 99 | (sizeof (union align)))*(sizeof (union align)); 100 | for (bp = freelist.free; bp; bp = bp->free) { 101 | if (bp->size > nbytes) { 102 | bp->size -= nbytes; 103 | ptr = (char *)bp->ptr + bp->size; 104 | if ((bp = dalloc(ptr, nbytes, file, line)) != NULL) { 105 | unsigned h = hash(ptr, htab); 106 | bp->link = htab[h]; 107 | htab[h] = bp; 108 | return ptr; 109 | } else 110 | { 111 | if (file == NULL) 112 | RAISE(Mem_Failed); 113 | else 114 | Except_raise(&Mem_Failed, file, line); 115 | } 116 | } 117 | if (bp == &freelist) { 118 | struct descriptor *newptr; 119 | if ((ptr = malloc(nbytes + NALLOC)) == NULL 120 | || (newptr = dalloc(ptr, nbytes + NALLOC, 121 | __FILE__, __LINE__)) == NULL) 122 | { 123 | if (file == NULL) 124 | RAISE(Mem_Failed); 125 | else 126 | Except_raise(&Mem_Failed, file, line); 127 | } 128 | newptr->free = freelist.free; 129 | freelist.free = newptr; 130 | } 131 | } 132 | assert(0); 133 | return NULL; 134 | } 135 | -------------------------------------------------------------------------------- /src/memcmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /*lint -e613 4 | memcmp is defined here because some vendors don't implement 5 | it, strcmp, or strncmp correctly; they must treat the bytes 6 | as unsigned chars. 7 | */ 8 | int memcmp(const void *s1, const void *s2, size_t n) { 9 | const unsigned char *cs1 = s1, *cs2 = s2; 10 | 11 | for ( ; n-- > 0; cs1++, cs2++) 12 | if (*cs1 != *cs2) 13 | return *cs1 - *cs2; 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/memmove.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /*lint -e613 4 | memmove is defined here because some vendors don't provide it at all 5 | and others do poor job (like calling malloc) 6 | */ 7 | void *memmove(void *s1, const void *s2, size_t n) { 8 | unsigned char *cs1; 9 | const unsigned char *cs2; 10 | 11 | if (n <= 0) 12 | return s1; 13 | cs1 = s1; 14 | cs2 = s2; 15 | if (cs1 < cs2) 16 | do 17 | *cs1++ = *cs2++; 18 | while (--n); 19 | else { 20 | cs1 += n; 21 | cs2 += n; 22 | do 23 | *--cs1 = *--cs2; 24 | while (--n); 25 | } 26 | return s1; 27 | } 28 | -------------------------------------------------------------------------------- /src/ring.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include "assert.h" 6 | #include "ring.h" 7 | #include "mem.h" 8 | #define T Ring_T 9 | struct T { 10 | struct node { 11 | struct node *llink, *rlink; 12 | void *value; 13 | } *head; 14 | int length; 15 | }; 16 | T Ring_new(void) { 17 | T ring; 18 | NEW0(ring); 19 | ring->head = NULL; 20 | return ring; 21 | } 22 | T Ring_ring(void *x, ...) { 23 | va_list ap; 24 | T ring = Ring_new(); 25 | va_start(ap, x); 26 | for ( ; x; x = va_arg(ap, void *)) 27 | Ring_addhi(ring, x); 28 | va_end(ap); 29 | return ring; 30 | } 31 | void Ring_free(T *ring) { 32 | struct node *p, *q; 33 | assert(ring && *ring); 34 | if ((p = (*ring)->head) != NULL) { 35 | int n = (*ring)->length; 36 | for ( ; n-- > 0; p = q) { 37 | q = p->rlink; 38 | FREE(p); 39 | } 40 | } 41 | FREE(*ring); 42 | } 43 | int Ring_length(T ring) { 44 | assert(ring); 45 | return ring->length; 46 | } 47 | void *Ring_get(T ring, int i) { 48 | struct node *q; 49 | assert(ring); 50 | assert(i >= 0 && i < ring->length); 51 | { 52 | int n; 53 | q = ring->head; 54 | if (i <= ring->length/2) 55 | for (n = i; n-- > 0; ) 56 | q = q->rlink; 57 | else 58 | for (n = ring->length - i; n-- > 0; ) 59 | q = q->llink; 60 | } 61 | return q->value; 62 | } 63 | void *Ring_put(T ring, int i, void *x) { 64 | struct node *q; 65 | void *prev; 66 | assert(ring); 67 | assert(i >= 0 && i < ring->length); 68 | { 69 | int n; 70 | q = ring->head; 71 | if (i <= ring->length/2) 72 | for (n = i; n-- > 0; ) 73 | q = q->rlink; 74 | else 75 | for (n = ring->length - i; n-- > 0; ) 76 | q = q->llink; 77 | } 78 | prev = q->value; 79 | q->value = x; 80 | return prev; 81 | } 82 | void *Ring_addhi(T ring, void *x) { 83 | struct node *p, *q; 84 | assert(ring); 85 | NEW(p); 86 | if ((q = ring->head) != NULL) 87 | { 88 | p->llink = q->llink; 89 | q->llink->rlink = p; 90 | p->rlink = q; 91 | q->llink = p; 92 | } 93 | else 94 | ring->head = p->llink = p->rlink = p; 95 | ring->length++; 96 | return p->value = x; 97 | } 98 | void *Ring_addlo(T ring, void *x) { 99 | assert(ring); 100 | Ring_addhi(ring, x); 101 | ring->head = ring->head->llink; 102 | return x; 103 | } 104 | void *Ring_add(T ring, int pos, void *x) { 105 | assert(ring); 106 | assert(pos >= -ring->length && pos<=ring->length+1); 107 | if (pos == 1 || pos == -ring->length) 108 | return Ring_addlo(ring, x); 109 | else if (pos == 0 || pos == ring->length + 1) 110 | return Ring_addhi(ring, x); 111 | else { 112 | struct node *p, *q; 113 | int i = pos < 0 ? pos + ring->length : pos - 1; 114 | { 115 | int n; 116 | q = ring->head; 117 | if (i <= ring->length/2) 118 | for (n = i; n-- > 0; ) 119 | q = q->rlink; 120 | else 121 | for (n = ring->length - i; n-- > 0; ) 122 | q = q->llink; 123 | } 124 | NEW(p); 125 | { 126 | p->llink = q->llink; 127 | q->llink->rlink = p; 128 | p->rlink = q; 129 | q->llink = p; 130 | } 131 | ring->length++; 132 | return p->value = x; 133 | } 134 | } 135 | void *Ring_remove(T ring, int i) { 136 | void *x; 137 | struct node *q; 138 | assert(ring); 139 | assert(ring->length > 0); 140 | assert(i >= 0 && i < ring->length); 141 | { 142 | int n; 143 | q = ring->head; 144 | if (i <= ring->length/2) 145 | for (n = i; n-- > 0; ) 146 | q = q->rlink; 147 | else 148 | for (n = ring->length - i; n-- > 0; ) 149 | q = q->llink; 150 | } 151 | if (i == 0) 152 | ring->head = ring->head->rlink; 153 | x = q->value; 154 | q->llink->rlink = q->rlink; 155 | q->rlink->llink = q->llink; 156 | FREE(q); 157 | if (--ring->length == 0) 158 | ring->head = NULL; 159 | return x; 160 | } 161 | void *Ring_remhi(T ring) { 162 | void *x; 163 | struct node *q; 164 | assert(ring); 165 | assert(ring->length > 0); 166 | q = ring->head->llink; 167 | x = q->value; 168 | q->llink->rlink = q->rlink; 169 | q->rlink->llink = q->llink; 170 | FREE(q); 171 | if (--ring->length == 0) 172 | ring->head = NULL; 173 | return x; 174 | } 175 | void *Ring_remlo(T ring) { 176 | assert(ring); 177 | assert(ring->length > 0); 178 | ring->head = ring->head->rlink; 179 | return Ring_remhi(ring); 180 | } 181 | void Ring_rotate(T ring, int n) { 182 | struct node *q; 183 | int i; 184 | assert(ring); 185 | assert(n >= -ring->length && n <= ring->length); 186 | if (n >= 0) 187 | i = n%ring->length; 188 | else 189 | i = n + ring->length; 190 | { 191 | int n; 192 | q = ring->head; 193 | if (i <= ring->length/2) 194 | for (n = i; n-- > 0; ) 195 | q = q->rlink; 196 | else 197 | for (n = ring->length - i; n-- > 0; ) 198 | q = q->llink; 199 | } 200 | ring->head = q; 201 | } 202 | -------------------------------------------------------------------------------- /src/seq.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include "assert.h" 6 | #include "seq.h" 7 | #include "array.h" 8 | #include "arrayrep.h" 9 | #include "mem.h" 10 | #define T Seq_T 11 | struct T { 12 | struct Array_T array; 13 | int length; 14 | int head; 15 | }; 16 | static void expand(T seq) { 17 | int n = seq->array.length; 18 | Array_resize(&seq->array, 2*n); 19 | if (seq->head > 0) 20 | { 21 | void **old = &((void **)seq->array.array)[seq->head]; 22 | memcpy(old+n, old, (n - seq->head)*sizeof (void *)); 23 | seq->head += n; 24 | } 25 | } 26 | T Seq_new(int hint) { 27 | T seq; 28 | assert(hint >= 0); 29 | NEW0(seq); 30 | if (hint == 0) 31 | hint = 16; 32 | ArrayRep_init(&seq->array, hint, sizeof (void *), 33 | ALLOC(hint*sizeof (void *))); 34 | return seq; 35 | } 36 | T Seq_seq(void *x, ...) { 37 | va_list ap; 38 | T seq = Seq_new(0); 39 | va_start(ap, x); 40 | for ( ; x; x = va_arg(ap, void *)) 41 | Seq_addhi(seq, x); 42 | va_end(ap); 43 | return seq; 44 | } 45 | void Seq_free(T *seq) { 46 | assert(seq && *seq); 47 | assert((void *)*seq == (void *)&(*seq)->array); 48 | Array_free((Array_T *)seq); 49 | } 50 | int Seq_length(T seq) { 51 | assert(seq); 52 | return seq->length; 53 | } 54 | void *Seq_get(T seq, int i) { 55 | assert(seq); 56 | assert(i >= 0 && i < seq->length); 57 | return ((void **)seq->array.array)[ 58 | (seq->head + i)%seq->array.length]; 59 | } 60 | void *Seq_put(T seq, int i, void *x) { 61 | void *prev; 62 | assert(seq); 63 | assert(i >= 0 && i < seq->length); 64 | prev = ((void **)seq->array.array)[ 65 | (seq->head + i)%seq->array.length]; 66 | ((void **)seq->array.array)[ 67 | (seq->head + i)%seq->array.length] = x; 68 | return prev; 69 | } 70 | void *Seq_remhi(T seq) { 71 | int i; 72 | assert(seq); 73 | assert(seq->length > 0); 74 | i = --seq->length; 75 | return ((void **)seq->array.array)[ 76 | (seq->head + i)%seq->array.length]; 77 | } 78 | void *Seq_remlo(T seq) { 79 | int i = 0; 80 | void *x; 81 | assert(seq); 82 | assert(seq->length > 0); 83 | x = ((void **)seq->array.array)[ 84 | (seq->head + i)%seq->array.length]; 85 | seq->head = (seq->head + 1)%seq->array.length; 86 | --seq->length; 87 | return x; 88 | } 89 | void *Seq_addhi(T seq, void *x) { 90 | int i; 91 | assert(seq); 92 | if (seq->length == seq->array.length) 93 | expand(seq); 94 | i = seq->length++; 95 | return ((void **)seq->array.array)[ 96 | (seq->head + i)%seq->array.length] = x; 97 | } 98 | void *Seq_addlo(T seq, void *x) { 99 | int i = 0; 100 | assert(seq); 101 | if (seq->length == seq->array.length) 102 | expand(seq); 103 | if (--seq->head < 0) 104 | seq->head = seq->array.length - 1; 105 | seq->length++; 106 | return ((void **)seq->array.array)[ 107 | (seq->head + i)%seq->array.length] = x; 108 | } 109 | -------------------------------------------------------------------------------- /src/set.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "mem.h" 5 | #include "assert.h" 6 | #include "arith.h" 7 | #include "set.h" 8 | #define T Set_T 9 | struct T { 10 | int length; 11 | unsigned timestamp; 12 | int (*cmp)(const void *x, const void *y); 13 | unsigned (*hash)(const void *x); 14 | int size; 15 | struct member { 16 | struct member *link; 17 | const void *member; 18 | } **buckets; 19 | }; 20 | static int cmpatom(const void *x, const void *y) { 21 | return x != y; 22 | } 23 | static unsigned hashatom(const void *x) { 24 | return (unsigned long)x>>2; 25 | } 26 | static T copy(T t, int hint) { 27 | T set; 28 | assert(t); 29 | set = Set_new(hint, t->cmp, t->hash); 30 | { int i; 31 | struct member *q; 32 | for (i = 0; i < t->size; i++) 33 | for (q = t->buckets[i]; q; q = q->link) 34 | { 35 | struct member *p; 36 | const void *member = q->member; 37 | int i = (*set->hash)(member)%set->size; 38 | NEW(p); 39 | p->member = member; 40 | p->link = set->buckets[i]; 41 | set->buckets[i] = p; 42 | set->length++; 43 | } 44 | } 45 | return set; 46 | } 47 | T Set_new(int hint, 48 | int cmp(const void *x, const void *y), 49 | unsigned hash(const void *x)) { 50 | T set; 51 | int i; 52 | static int primes[] = { 509, 509, 1021, 2053, 4093, 53 | 8191, 16381, 32771, 65521, INT_MAX }; 54 | assert(hint >= 0); 55 | for (i = 1; primes[i] < hint; i++) 56 | ; 57 | set = ALLOC(sizeof (*set) + 58 | primes[i-1]*sizeof (set->buckets[0])); 59 | set->size = primes[i-1]; 60 | set->cmp = cmp ? cmp : cmpatom; 61 | set->hash = hash ? hash : hashatom; 62 | set->buckets = (struct member **)(set + 1); 63 | for (i = 0; i < set->size; i++) 64 | set->buckets[i] = NULL; 65 | set->length = 0; 66 | set->timestamp = 0; 67 | return set; 68 | } 69 | int Set_member(T set, const void *member) { 70 | int i; 71 | struct member *p; 72 | assert(set); 73 | assert(member); 74 | i = (*set->hash)(member)%set->size; 75 | for (p = set->buckets[i]; p; p = p->link) 76 | if ((*set->cmp)(member, p->member) == 0) 77 | break; 78 | return p != NULL; 79 | } 80 | void Set_put(T set, const void *member) { 81 | int i; 82 | struct member *p; 83 | assert(set); 84 | assert(member); 85 | i = (*set->hash)(member)%set->size; 86 | for (p = set->buckets[i]; p; p = p->link) 87 | if ((*set->cmp)(member, p->member) == 0) 88 | break; 89 | if (p == NULL) { 90 | NEW(p); 91 | p->member = member; 92 | p->link = set->buckets[i]; 93 | set->buckets[i] = p; 94 | set->length++; 95 | } else 96 | p->member = member; 97 | set->timestamp++; 98 | } 99 | void *Set_remove(T set, const void *member) { 100 | int i; 101 | struct member **pp; 102 | assert(set); 103 | assert(member); 104 | set->timestamp++; 105 | i = (*set->hash)(member)%set->size; 106 | for (pp = &set->buckets[i]; *pp; pp = &(*pp)->link) 107 | if ((*set->cmp)(member, (*pp)->member) == 0) { 108 | struct member *p = *pp; 109 | *pp = p->link; 110 | member = p->member; 111 | FREE(p); 112 | set->length--; 113 | return (void *)member; 114 | } 115 | return NULL; 116 | } 117 | int Set_length(T set) { 118 | assert(set); 119 | return set->length; 120 | } 121 | void Set_free(T *set) { 122 | assert(set && *set); 123 | if ((*set)->length > 0) { 124 | int i; 125 | struct member *p, *q; 126 | for (i = 0; i < (*set)->size; i++) 127 | for (p = (*set)->buckets[i]; p; p = q) { 128 | q = p->link; 129 | FREE(p); 130 | } 131 | } 132 | FREE(*set); 133 | } 134 | void Set_map(T set, 135 | void apply(const void *member, void *cl), void *cl) { 136 | int i; 137 | unsigned stamp; 138 | struct member *p; 139 | assert(set); 140 | assert(apply); 141 | stamp = set->timestamp; 142 | for (i = 0; i < set->size; i++) 143 | for (p = set->buckets[i]; p; p = p->link) { 144 | apply(p->member, cl); 145 | assert(set->timestamp == stamp); 146 | } 147 | } 148 | void **Set_toArray(T set, void *end) { 149 | int i, j = 0; 150 | void **array; 151 | struct member *p; 152 | assert(set); 153 | array = ALLOC((set->length + 1)*sizeof (*array)); 154 | for (i = 0; i < set->size; i++) 155 | for (p = set->buckets[i]; p; p = p->link) 156 | array[j++] = (void *)p->member; 157 | array[j] = end; 158 | return array; 159 | } 160 | T Set_union(T s, T t) { 161 | if (s == NULL) { 162 | assert(t); 163 | return copy(t, t->size); 164 | } else if (t == NULL) 165 | return copy(s, s->size); 166 | else { 167 | T set = copy(s, Arith_max(s->size, t->size)); 168 | assert(s->cmp == t->cmp && s->hash == t->hash); 169 | { int i; 170 | struct member *q; 171 | for (i = 0; i < t->size; i++) 172 | for (q = t->buckets[i]; q; q = q->link) 173 | Set_put(set, q->member); 174 | } 175 | return set; 176 | } 177 | } 178 | T Set_inter(T s, T t) { 179 | if (s == NULL) { 180 | assert(t); 181 | return Set_new(t->size, t->cmp, t->hash); 182 | } else if (t == NULL) 183 | return Set_new(s->size, s->cmp, s->hash); 184 | else if (s->length < t->length) 185 | return Set_inter(t, s); 186 | else { 187 | T set = Set_new(Arith_min(s->size, t->size), 188 | s->cmp, s->hash); 189 | assert(s->cmp == t->cmp && s->hash == t->hash); 190 | { int i; 191 | struct member *q; 192 | for (i = 0; i < t->size; i++) 193 | for (q = t->buckets[i]; q; q = q->link) 194 | if (Set_member(s, q->member)) 195 | { 196 | struct member *p; 197 | const void *member = q->member; 198 | int i = (*set->hash)(member)%set->size; 199 | NEW(p); 200 | p->member = member; 201 | p->link = set->buckets[i]; 202 | set->buckets[i] = p; 203 | set->length++; 204 | } 205 | } 206 | return set; 207 | } 208 | } 209 | T Set_minus(T t, T s) { 210 | if (t == NULL){ 211 | assert(s); 212 | return Set_new(s->size, s->cmp, s->hash); 213 | } else if (s == NULL) 214 | return copy(t, t->size); 215 | else { 216 | T set = Set_new(Arith_min(s->size, t->size), 217 | s->cmp, s->hash); 218 | assert(s->cmp == t->cmp && s->hash == t->hash); 219 | { int i; 220 | struct member *q; 221 | for (i = 0; i < t->size; i++) 222 | for (q = t->buckets[i]; q; q = q->link) 223 | if (!Set_member(s, q->member)) 224 | { 225 | struct member *p; 226 | const void *member = q->member; 227 | int i = (*set->hash)(member)%set->size; 228 | NEW(p); 229 | p->member = member; 230 | p->link = set->buckets[i]; 231 | set->buckets[i] = p; 232 | set->length++; 233 | } 234 | } 235 | return set; 236 | } 237 | } 238 | T Set_diff(T s, T t) { 239 | if (s == NULL) { 240 | assert(t); 241 | return copy(t, t->size); 242 | } else if (t == NULL) 243 | return copy(s, s->size); 244 | else { 245 | T set = Set_new(Arith_min(s->size, t->size), 246 | s->cmp, s->hash); 247 | assert(s->cmp == t->cmp && s->hash == t->hash); 248 | { int i; 249 | struct member *q; 250 | for (i = 0; i < t->size; i++) 251 | for (q = t->buckets[i]; q; q = q->link) 252 | if (!Set_member(s, q->member)) 253 | { 254 | struct member *p; 255 | const void *member = q->member; 256 | int i = (*set->hash)(member)%set->size; 257 | NEW(p); 258 | p->member = member; 259 | p->link = set->buckets[i]; 260 | set->buckets[i] = p; 261 | set->length++; 262 | } 263 | } 264 | { T u = t; t = s; s = u; } 265 | { int i; 266 | struct member *q; 267 | for (i = 0; i < t->size; i++) 268 | for (q = t->buckets[i]; q; q = q->link) 269 | if (!Set_member(s, q->member)) 270 | { 271 | struct member *p; 272 | const void *member = q->member; 273 | int i = (*set->hash)(member)%set->size; 274 | NEW(p); 275 | p->member = member; 276 | p->link = set->buckets[i]; 277 | set->buckets[i] = p; 278 | set->length++; 279 | } 280 | } 281 | return set; 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/stack.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include "assert.h" 4 | #include "mem.h" 5 | #include "stack.h" 6 | #define T Stack_T 7 | struct T { 8 | int count; 9 | struct elem { 10 | void *x; 11 | struct elem *link; 12 | } *head; 13 | }; 14 | T Stack_new(void) { 15 | T stk; 16 | NEW(stk); 17 | stk->count = 0; 18 | stk->head = NULL; 19 | return stk; 20 | } 21 | int Stack_empty(T stk) { 22 | assert(stk); 23 | return stk->count == 0; 24 | } 25 | void Stack_push(T stk, void *x) { 26 | struct elem *t; 27 | assert(stk); 28 | NEW(t); 29 | t->x = x; 30 | t->link = stk->head; 31 | stk->head = t; 32 | stk->count++; 33 | } 34 | void *Stack_pop(T stk) { 35 | void *x; 36 | struct elem *t; 37 | assert(stk); 38 | assert(stk->count > 0); 39 | t = stk->head; 40 | stk->head = t->link; 41 | stk->count--; 42 | x = t->x; 43 | FREE(t); 44 | return x; 45 | } 46 | void Stack_free(T *stk) { 47 | struct elem *t, *u; 48 | assert(stk && *stk); 49 | for (t = (*stk)->head; t; t = u) { 50 | u = t->link; 51 | FREE(t); 52 | } 53 | FREE(*stk); 54 | } 55 | -------------------------------------------------------------------------------- /src/str.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "fmt.h" 6 | #include "str.h" 7 | #include "mem.h" 8 | #define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1) 9 | #define convert(s, i, j) do { int len; \ 10 | assert(s); len = strlen(s); \ 11 | i = idx(i, len); j = idx(j, len); \ 12 | if (i > j) { int t = i; i = j; j = t; } \ 13 | assert(i >= 0 && j <= len); } while (0) 14 | char *Str_sub(const char *s, int i, int j) { 15 | char *str, *p; 16 | convert(s, i, j); 17 | p = str = ALLOC(j - i + 1); 18 | while (i < j) 19 | *p++ = s[i++]; 20 | *p = '\0'; 21 | return str; 22 | } 23 | char *Str_dup(const char *s, int i, int j, int n) { 24 | int k; 25 | char *str, *p; 26 | assert(n >= 0); 27 | convert(s, i, j); 28 | p = str = ALLOC(n*(j - i) + 1); 29 | if (j - i > 0) 30 | while (n-- > 0) 31 | for (k = i; k < j; k++) 32 | *p++ = s[k]; 33 | *p = '\0'; 34 | return str; 35 | } 36 | char *Str_reverse(const char *s, int i, int j) { 37 | char *str, *p; 38 | convert(s, i, j); 39 | p = str = ALLOC(j - i + 1); 40 | while (j > i) 41 | *p++ = s[--j]; 42 | *p = '\0'; 43 | return str; 44 | } 45 | char *Str_cat(const char *s1, int i1, int j1, 46 | const char *s2, int i2, int j2) { 47 | char *str, *p; 48 | convert(s1, i1, j1); 49 | convert(s2, i2, j2); 50 | p = str = ALLOC(j1 - i1 + j2 - i2 + 1); 51 | while (i1 < j1) 52 | *p++ = s1[i1++]; 53 | while (i2 < j2) 54 | *p++ = s2[i2++]; 55 | *p = '\0'; 56 | return str; 57 | } 58 | char *Str_catv(const char *s, ...) { 59 | char *str, *p; 60 | const char *save = s; 61 | int i, j, len = 0; 62 | va_list ap; 63 | va_start(ap, s); 64 | while (s) { 65 | i = va_arg(ap, int); 66 | j = va_arg(ap, int); 67 | convert(s, i, j); 68 | len += j - i; 69 | s = va_arg(ap, const char *); 70 | } 71 | va_end(ap); 72 | p = str = ALLOC(len + 1); 73 | s = save; 74 | va_start(ap, s); 75 | while (s) { 76 | i = va_arg(ap, int); 77 | j = va_arg(ap, int); 78 | convert(s, i, j); 79 | while (i < j) 80 | *p++ = s[i++]; 81 | s = va_arg(ap, const char *); 82 | } 83 | va_end(ap); 84 | *p = '\0'; 85 | return str; 86 | } 87 | char *Str_map(const char *s, int i, int j, 88 | const char *from, const char *to) { 89 | static char map[256] = { 0 }; 90 | if (from && to) { 91 | unsigned c; 92 | for (c = 0; c < sizeof map; c++) 93 | map[c] = c; 94 | while (*from && *to) 95 | map[(unsigned char)*from++] = *to++; 96 | assert(*from == 0 && *to == 0); 97 | } else { 98 | assert(from == NULL && to == NULL && s); 99 | assert(map['a']); 100 | } 101 | if (s) { 102 | char *str, *p; 103 | convert(s, i, j); 104 | p = str = ALLOC(j - i + 1); 105 | while (i < j) 106 | *p++ = map[(unsigned char)s[i++]]; 107 | *p = '\0'; 108 | return str; 109 | } else 110 | return NULL; 111 | } 112 | int Str_pos(const char *s, int i) { 113 | int len; 114 | assert(s); 115 | len = strlen(s); 116 | i = idx(i, len); 117 | assert(i >= 0 && i <= len); 118 | return i + 1; 119 | } 120 | int Str_len(const char *s, int i, int j) { 121 | convert(s, i, j); 122 | return j - i; 123 | } 124 | int Str_cmp(const char *s1, int i1, int j1, 125 | const char *s2, int i2, int j2) { 126 | convert(s1, i1, j1); 127 | convert(s2, i2, j2); 128 | s1 += i1; 129 | s2 += i2; 130 | if (j1 - i1 < j2 - i2) { 131 | int cond = strncmp(s1, s2, j1 - i1); 132 | return cond == 0 ? -1 : cond; 133 | } else if (j1 - i1 > j2 - i2) { 134 | int cond = strncmp(s1, s2, j2 - i2); 135 | return cond == 0 ? +1 : cond; 136 | } else 137 | return strncmp(s1, s2, j1 - i1); 138 | } 139 | int Str_chr(const char *s, int i, int j, int c) { 140 | convert(s, i, j); 141 | for ( ; i < j; i++) 142 | if (s[i] == c) 143 | return i + 1; 144 | return 0; 145 | } 146 | int Str_rchr(const char *s, int i, int j, int c) { 147 | convert(s, i, j); 148 | while (j > i) 149 | if (s[--j] == c) 150 | return j + 1; 151 | return 0; 152 | } 153 | int Str_upto(const char *s, int i, int j, 154 | const char *set) { 155 | assert(set); 156 | convert(s, i, j); 157 | for ( ; i < j; i++) 158 | if (strchr(set, s[i])) 159 | return i + 1; 160 | return 0; 161 | } 162 | int Str_rupto(const char *s, int i, int j, 163 | const char *set) { 164 | assert(set); 165 | convert(s, i, j); 166 | while (j > i) 167 | if (strchr(set, s[--j])) 168 | return j + 1; 169 | return 0; 170 | } 171 | int Str_find(const char *s, int i, int j, 172 | const char *str) { 173 | int len; 174 | convert(s, i, j); 175 | assert(str); 176 | len = strlen(str); 177 | if (len == 0) 178 | return i + 1; 179 | else if (len == 1) { 180 | for ( ; i < j; i++) 181 | if (s[i] == *str) 182 | return i + 1; 183 | } else 184 | for ( ; i + len <= j; i++) 185 | if ((strncmp(&s[i], str, len) == 0)) 186 | return i + 1; 187 | return 0; 188 | } 189 | int Str_rfind(const char *s, int i, int j, 190 | const char *str) { 191 | int len; 192 | convert(s, i, j); 193 | assert(str); 194 | len = strlen(str); 195 | if (len == 0) 196 | return j + 1; 197 | else if (len == 1) { 198 | while (j > i) 199 | if (s[--j] == *str) 200 | return j + 1; 201 | } else 202 | for ( ; j - len >= i; j--) 203 | if (strncmp(&s[j-len], str, len) == 0) 204 | return j - len + 1; 205 | return 0; 206 | } 207 | int Str_any(const char *s, int i, const char *set) { 208 | int len; 209 | assert(s); 210 | assert(set); 211 | len = strlen(s); 212 | i = idx(i, len); 213 | assert(i >= 0 && i <= len); 214 | if (i < len && strchr(set, s[i])) 215 | return i + 2; 216 | return 0; 217 | } 218 | int Str_many(const char *s, int i, int j, 219 | const char *set) { 220 | assert(set); 221 | convert(s, i, j); 222 | if (i < j && strchr(set, s[i])) { 223 | do 224 | i++; 225 | while (i < j && strchr(set, s[i])); 226 | return i + 1; 227 | } 228 | return 0; 229 | } 230 | int Str_rmany(const char *s, int i, int j, 231 | const char *set) { 232 | assert(set); 233 | convert(s, i, j); 234 | if (j > i && strchr(set, s[j-1])) { 235 | do 236 | --j; 237 | while (j >= i && strchr(set, s[j])); 238 | return j + 2; 239 | } 240 | return 0; 241 | } 242 | int Str_match(const char *s, int i, int j, 243 | const char *str) { 244 | int len; 245 | convert(s, i, j); 246 | assert(str); 247 | len = strlen(str); 248 | if (len == 0) 249 | return i + 1; 250 | else if (len == 1) { 251 | if (i < j && s[i] == *str) 252 | return i + 2; 253 | } else if (i + len <= j && (strncmp(&s[i], str, len) == 0)) 254 | return i + len + 1; 255 | return 0; 256 | } 257 | int Str_rmatch(const char *s, int i, int j, 258 | const char *str) { 259 | int len; 260 | convert(s, i, j); 261 | assert(str); 262 | len = strlen(str); 263 | if (len == 0) 264 | return j + 1; 265 | else if (len == 1) { 266 | if (j > i && s[j-1] == *str) 267 | return j; 268 | } else if (j - len >= i 269 | && strncmp(&s[j-len], str, len) == 0) 270 | return j - len + 1; 271 | return 0; 272 | } 273 | void Str_fmt(int code, va_list_box *box, 274 | int put(int c, void *cl), void *cl, 275 | unsigned char flags[], int width, int precision) { 276 | char *s; 277 | int i, j; 278 | assert(box && flags); 279 | s = va_arg(box->ap, char *); 280 | i = va_arg(box->ap, int); 281 | j = va_arg(box->ap, int); 282 | convert(s, i, j); 283 | Fmt_puts(s + i, j - i, put, cl, flags, 284 | width, precision); 285 | } 286 | -------------------------------------------------------------------------------- /src/strerror.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /*lint -e613 5 | strerror is defined here because some vendors don't provide it. 6 | */ 7 | char *strerror(int errnum) { 8 | extern int sys_nerr; 9 | extern char *sys_errlist[]; 10 | static char null[1] = { 0 }; 11 | 12 | if (errnum <= 0) 13 | return null; 14 | else if (errnum >= sys_nerr) { 15 | static char errmsg[50]; 16 | sprintf(errmsg, "error %d", errnum); 17 | return errmsg; 18 | } else 19 | return sys_errlist[errnum]; 20 | } 21 | -------------------------------------------------------------------------------- /src/strncmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /*lint -e613 4 | strncmp is defined here because some vendors don't implement 5 | it, strcmp, or memcmp correctly; they must treat the bytes 6 | as unsigned chars. 7 | */ 8 | int strncmp(const char *s1, const char *s2, size_t n) { 9 | for ( ; n-- > 0; s1++, s2++) 10 | if (*s1 != *s2) 11 | return (unsigned char)*s1 - (unsigned char)*s2; 12 | else if (*s1 == 0) 13 | return 0; 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /src/swtch.s: -------------------------------------------------------------------------------- 1 | #if alpha 2 | .globl _swtch 3 | .ent _swtch 4 | _swtch: lda $sp,-112($sp) # allocate _swtch's frame 5 | .frame $sp,112,$26 6 | .fmask 0x3f0000,-112 7 | stt $f21,0($sp) # save from's registers 8 | stt $f20,8($sp) 9 | stt $f19,16($sp) 10 | stt $f18,24($sp) 11 | stt $f17,32($sp) 12 | stt $f16,40($sp) 13 | .mask 0x400fe00,-64 14 | stq $26,48+0($sp) 15 | stq $15,48+8($sp) 16 | stq $14,48+16($sp) 17 | stq $13,48+24($sp) 18 | stq $12,48+32($sp) 19 | stq $11,48+40($sp) 20 | stq $10,48+48($sp) 21 | stq $9,48+56($sp) 22 | .prologue 0 23 | stq $sp,0($16) # save from's stack pointer 24 | ldq $sp,0($17) # restore to's stack pointer 25 | ldt $f21,0($sp) # restore to's registers 26 | ldt $f20,8($sp) 27 | ldt $f19,16($sp) 28 | ldt $f18,24($sp) 29 | ldt $f17,32($sp) 30 | ldt $f16,40($sp) 31 | ldq $26,48+0($sp) 32 | ldq $15,48+8($sp) 33 | ldq $14,48+16($sp) 34 | ldq $13,48+24($sp) 35 | ldq $12,48+32($sp) 36 | ldq $11,48+40($sp) 37 | ldq $10,48+48($sp) 38 | ldq $9,48+56($sp) 39 | lda $sp,112($sp) # deallocate frame 40 | ret $31,($26) 41 | .end _swtch 42 | .globl _start 43 | .ent _start 44 | _start: .frame $sp,0,$26 45 | .mask 0x0,0 46 | .prologue 0 47 | mov $14,$16 # register 14 holds args 48 | mov $15,$27 # register 15 holds apply 49 | jsr $26,($27) # call apply 50 | ldgp $26,0($26) # reload the global pointer 51 | mov $0,$16 # Thread_exit(apply(args)) 52 | mov $13,$27 # register 13 has Thread_exit 53 | jsr $26,($27) 54 | call_pal 0 55 | .end _start 56 | .globl _ENDMONITOR 57 | _ENDMONITOR: 58 | #elif sparc 59 | .global __swtch 60 | .align 4 61 | .proc 4 62 | __swtch: save %sp,-(8+64),%sp 63 | st %fp,[%sp+64+0] ! save from's frame pointer 64 | st %i7,[%sp+64+4] ! save from's return address 65 | ta 3 ! flush from's registers 66 | st %sp,[%i0] ! save from's stack pointer 67 | ld [%i1],%sp ! load to's stack pointer 68 | ld [%sp+64+0],%fp ! restore to's frame pointer 69 | ld [%sp+64+4],%i7 ! restore to's return address 70 | ret ! continue execution of to 71 | restore 72 | .global __start 73 | .align 4 74 | .proc 4 75 | __start: ld [%sp+64+4],%o0 76 | ld [%sp+64],%o1 77 | call %o1; nop 78 | call _Thread_exit; nop 79 | unimp 0 80 | .global __ENDMONITOR 81 | __ENDMONITOR: 82 | #elif mips 83 | .text 84 | .globl _swtch 85 | .align 2 86 | .ent _swtch 87 | .set reorder 88 | _swtch: .frame $sp,88,$31 89 | subu $sp,88 90 | .fmask 0xfff00000,-48 91 | s.d $f20,0($sp) 92 | s.d $f22,8($sp) 93 | s.d $f24,16($sp) 94 | s.d $f26,24($sp) 95 | s.d $f28,32($sp) 96 | s.d $f30,40($sp) 97 | .mask 0xc0ff0000,-4 98 | sw $16,48+0($sp) 99 | sw $17,48+4($sp) 100 | sw $18,48+8($sp) 101 | sw $19,48+12($sp) 102 | sw $20,48+16($sp) 103 | sw $21,48+20($sp) 104 | sw $22,48+24($sp) 105 | sw $23,48+28($sp) 106 | sw $30,48+32($sp) 107 | sw $31,48+36($sp) 108 | sw $sp,0($4) 109 | lw $sp,0($5) 110 | l.d $f20,0($sp) 111 | l.d $f22,8($sp) 112 | l.d $f24,16($sp) 113 | l.d $f26,24($sp) 114 | l.d $f28,32($sp) 115 | l.d $f30,40($sp) 116 | lw $16,48+0($sp) 117 | lw $17,48+4($sp) 118 | lw $18,48+8($sp) 119 | lw $19,48+12($sp) 120 | lw $20,48+16($sp) 121 | lw $21,48+20($sp) 122 | lw $22,48+24($sp) 123 | lw $23,48+28($sp) 124 | lw $30,48+32($sp) 125 | lw $31,48+36($sp) 126 | addu $sp,88 127 | j $31 128 | .globl _start 129 | _start: move $4,$23 # register 23 holds args 130 | move $25,$30 # register 30 holds apply 131 | jal $25 132 | move $4,$2 # Thread_exit(apply(p)) 133 | move $25,$21 # register 21 holds Thread_exit 134 | jal $25 135 | syscall 136 | .end _swtch 137 | .globl _ENDMONITOR 138 | _ENDMONITOR: 139 | #elif (linux || __APPLE__) && i386 140 | .align 4 141 | #if __APPLE__ 142 | .globl __swtch 143 | __swtch: 144 | #else 145 | .globl _swtch 146 | _swtch: 147 | #endif 148 | subl $16,%esp 149 | movl %ebx,0(%esp) 150 | movl %esi,4(%esp) 151 | movl %edi,8(%esp) 152 | movl %ebp,12(%esp) 153 | movl 20(%esp),%eax 154 | movl %esp,0(%eax) 155 | movl 24(%esp),%eax 156 | movl 0(%eax),%esp 157 | movl 0(%esp),%ebx 158 | movl 4(%esp),%esi 159 | movl 8(%esp),%edi 160 | movl 12(%esp),%ebp 161 | addl $16,%esp 162 | ret 163 | .align 4 164 | .globl __thrstart 165 | .globl _thrstart 166 | __thrstart: 167 | _thrstart: 168 | pushl %edi # stack is 16-byte aligned after this push 169 | call *%esi 170 | subl $12,%esp # ensure stack is 16-byte aligned before the call 171 | pushl %eax 172 | #if __APPLE__ 173 | call _Thread_exit 174 | #else 175 | call Thread_exit 176 | #endif 177 | .globl __ENDMONITOR 178 | .globl _ENDMONITOR 179 | __ENDMONITOR: 180 | _ENDMONITOR: 181 | #else 182 | Unsupported platform 183 | #endif 184 | -------------------------------------------------------------------------------- /src/table.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "mem.h" 5 | #include "assert.h" 6 | #include "table.h" 7 | #define T Table_T 8 | struct T { 9 | int size; 10 | int (*cmp)(const void *x, const void *y); 11 | unsigned (*hash)(const void *key); 12 | int length; 13 | unsigned timestamp; 14 | struct binding { 15 | struct binding *link; 16 | const void *key; 17 | void *value; 18 | } **buckets; 19 | }; 20 | static int cmpatom(const void *x, const void *y) { 21 | return x != y; 22 | } 23 | static unsigned hashatom(const void *key) { 24 | return (unsigned long)key>>2; 25 | } 26 | T Table_new(int hint, 27 | int cmp(const void *x, const void *y), 28 | unsigned hash(const void *key)) { 29 | T table; 30 | int i; 31 | static int primes[] = { 509, 509, 1021, 2053, 4093, 32 | 8191, 16381, 32771, 65521, INT_MAX }; 33 | assert(hint >= 0); 34 | for (i = 1; primes[i] < hint; i++) 35 | ; 36 | table = ALLOC(sizeof (*table) + 37 | primes[i-1]*sizeof (table->buckets[0])); 38 | table->size = primes[i-1]; 39 | table->cmp = cmp ? cmp : cmpatom; 40 | table->hash = hash ? hash : hashatom; 41 | table->buckets = (struct binding **)(table + 1); 42 | for (i = 0; i < table->size; i++) 43 | table->buckets[i] = NULL; 44 | table->length = 0; 45 | table->timestamp = 0; 46 | return table; 47 | } 48 | void *Table_get(T table, const void *key) { 49 | int i; 50 | struct binding *p; 51 | assert(table); 52 | assert(key); 53 | i = (*table->hash)(key)%table->size; 54 | for (p = table->buckets[i]; p; p = p->link) 55 | if ((*table->cmp)(key, p->key) == 0) 56 | break; 57 | return p ? p->value : NULL; 58 | } 59 | void *Table_put(T table, const void *key, void *value) { 60 | int i; 61 | struct binding *p; 62 | void *prev; 63 | assert(table); 64 | assert(key); 65 | i = (*table->hash)(key)%table->size; 66 | for (p = table->buckets[i]; p; p = p->link) 67 | if ((*table->cmp)(key, p->key) == 0) 68 | break; 69 | if (p == NULL) { 70 | NEW(p); 71 | p->key = key; 72 | p->link = table->buckets[i]; 73 | table->buckets[i] = p; 74 | table->length++; 75 | prev = NULL; 76 | } else 77 | prev = p->value; 78 | p->value = value; 79 | table->timestamp++; 80 | return prev; 81 | } 82 | int Table_length(T table) { 83 | assert(table); 84 | return table->length; 85 | } 86 | void Table_map(T table, 87 | void apply(const void *key, void **value, void *cl), 88 | void *cl) { 89 | int i; 90 | unsigned stamp; 91 | struct binding *p; 92 | assert(table); 93 | assert(apply); 94 | stamp = table->timestamp; 95 | for (i = 0; i < table->size; i++) 96 | for (p = table->buckets[i]; p; p = p->link) { 97 | apply(p->key, &p->value, cl); 98 | assert(table->timestamp == stamp); 99 | } 100 | } 101 | void *Table_remove(T table, const void *key) { 102 | int i; 103 | struct binding **pp; 104 | assert(table); 105 | assert(key); 106 | table->timestamp++; 107 | i = (*table->hash)(key)%table->size; 108 | for (pp = &table->buckets[i]; *pp; pp = &(*pp)->link) 109 | if ((*table->cmp)(key, (*pp)->key) == 0) { 110 | struct binding *p = *pp; 111 | void *value = p->value; 112 | *pp = p->link; 113 | FREE(p); 114 | table->length--; 115 | return value; 116 | } 117 | return NULL; 118 | } 119 | void **Table_toArray(T table, void *end) { 120 | int i, j = 0; 121 | void **array; 122 | struct binding *p; 123 | assert(table); 124 | array = ALLOC((2*table->length + 1)*sizeof (*array)); 125 | for (i = 0; i < table->size; i++) 126 | for (p = table->buckets[i]; p; p = p->link) { 127 | array[j++] = (void *)p->key; 128 | array[j++] = p->value; 129 | } 130 | array[j] = end; 131 | return array; 132 | } 133 | void Table_free(T *table) { 134 | assert(table && *table); 135 | if ((*table)->length > 0) { 136 | int i; 137 | struct binding *p, *q; 138 | for (i = 0; i < (*table)->size; i++) 139 | for (p = (*table)->buckets[i]; p; p = q) { 140 | q = p->link; 141 | FREE(p); 142 | } 143 | } 144 | FREE(*table); 145 | } 146 | -------------------------------------------------------------------------------- /src/text.c: -------------------------------------------------------------------------------- 1 | static const char *rcsid = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "fmt.h" 6 | #include "text.h" 7 | #include "mem.h" 8 | #define T Text_T 9 | #define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1) 10 | #define isatend(s, n) ((s).str+(s).len == current->avail\ 11 | && current->avail + (n) <= current->limit) 12 | #define equal(s, i, t) \ 13 | (memcmp(&(s).str[i], (t).str, (t).len) == 0) 14 | struct Text_save_T { 15 | struct chunk *current; 16 | char *avail; 17 | }; 18 | static char cset[] = 19 | "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" 20 | "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" 21 | "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" 22 | "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" 23 | "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" 24 | "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" 25 | "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" 26 | "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" 27 | "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" 28 | "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" 29 | "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" 30 | "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" 31 | "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" 32 | "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" 33 | "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" 34 | "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" 35 | ; 36 | const T Text_cset = { 256, cset }; 37 | const T Text_ascii = { 127, cset }; 38 | const T Text_ucase = { 26, cset + 'A' }; 39 | const T Text_lcase = { 26, cset + 'a' }; 40 | const T Text_digits = { 10, cset + '0' }; 41 | const T Text_null = { 0, cset }; 42 | static struct chunk { 43 | struct chunk *link; 44 | char *avail; 45 | char *limit; 46 | } head = { NULL, NULL, NULL }, *current = &head; 47 | static char *alloc(int len) { 48 | assert(len >= 0); 49 | if (current->avail + len > current->limit) { 50 | current = current->link = 51 | ALLOC(sizeof (*current) + 10*1024 + len); 52 | current->avail = (char *)(current + 1); 53 | current->limit = current->avail + 10*1024 + len; 54 | current->link = NULL; 55 | } 56 | current->avail += len; 57 | return current->avail - len; 58 | } 59 | int Text_pos(T s, int i) { 60 | assert(s.len >= 0 && s.str); 61 | i = idx(i, s.len); 62 | assert(i >= 0 && i <= s.len); 63 | return i + 1; 64 | } 65 | T Text_box(const char *str, int len) { 66 | T text; 67 | assert(str); 68 | assert(len >= 0); 69 | text.str = str; 70 | text.len = len; 71 | return text; 72 | } 73 | T Text_sub(T s, int i, int j) { 74 | T text; 75 | assert(s.len >= 0 && s.str); 76 | i = idx(i, s.len); 77 | j = idx(j, s.len); 78 | if (i > j) { int t = i; i = j; j = t; } 79 | assert(i >= 0 && j <= s.len); 80 | text.len = j - i; 81 | text.str = s.str + i; 82 | return text; 83 | } 84 | T Text_put(const char *str) { 85 | T text; 86 | assert(str); 87 | text.len = strlen(str); 88 | text.str = memcpy(alloc(text.len), str, text.len); 89 | return text; 90 | } 91 | char *Text_get(char *str, int size, T s) { 92 | assert(s.len >= 0 && s.str); 93 | if (str == NULL) 94 | str = ALLOC(s.len + 1); 95 | else 96 | assert(size >= s.len + 1); 97 | memcpy(str, s.str, s.len); 98 | str[s.len] = '\0'; 99 | return str; 100 | } 101 | T Text_dup(T s, int n) { 102 | assert(s.len >= 0 && s.str); 103 | assert(n >= 0); 104 | if (n == 0 || s.len == 0) 105 | return Text_null; 106 | if (n == 1) 107 | return s; 108 | { 109 | T text; 110 | char *p; 111 | text.len = n*s.len; 112 | if (isatend(s, text.len - s.len)) { 113 | text.str = s.str; 114 | p = alloc(text.len - s.len); 115 | n--; 116 | } else 117 | text.str = p = alloc(text.len); 118 | for ( ; n-- > 0; p += s.len) 119 | memcpy(p, s.str, s.len); 120 | return text; 121 | } 122 | } 123 | T Text_cat(T s1, T s2) { 124 | assert(s1.len >= 0 && s1.str); 125 | assert(s2.len >= 0 && s2.str); 126 | if (s1.len == 0) 127 | return s2; 128 | if (s2.len == 0) 129 | return s1; 130 | if (s1.str + s1.len == s2.str) { 131 | s1.len += s2.len; 132 | return s1; 133 | } 134 | { 135 | T text; 136 | text.len = s1.len + s2.len; 137 | if (isatend(s1, s2.len)) { 138 | text.str = s1.str; 139 | memcpy(alloc(s2.len), s2.str, s2.len); 140 | } else { 141 | char *p; 142 | text.str = p = alloc(s1.len + s2.len); 143 | memcpy(p, s1.str, s1.len); 144 | memcpy(p + s1.len, s2.str, s2.len); 145 | } 146 | return text; 147 | } 148 | } 149 | T Text_reverse(T s) { 150 | assert(s.len >= 0 && s.str); 151 | if (s.len == 0) 152 | return Text_null; 153 | else if (s.len == 1) 154 | return s; 155 | else { 156 | T text; 157 | char *p; 158 | int i = s.len; 159 | text.len = s.len; 160 | text.str = p = alloc(s.len); 161 | while (--i >= 0) 162 | *p++ = s.str[i]; 163 | return text; 164 | } 165 | } 166 | T Text_map(T s, const T *from, const T *to) { 167 | static char map[256]; 168 | static int inited = 0; 169 | assert(s.len >= 0 && s.str); 170 | if (from && to) { 171 | int k; 172 | for (k = 0; k < (int)sizeof map; k++) 173 | map[k] = k; 174 | assert(from->len == to->len); 175 | for (k = 0; k < from->len; k++) 176 | map[(unsigned char)from->str[k]] = to->str[k]; 177 | inited = 1; 178 | } else { 179 | assert(from == NULL && to == NULL); 180 | assert(inited); 181 | } 182 | if (s.len == 0) 183 | return Text_null; 184 | else { 185 | T text; 186 | int i; 187 | char *p; 188 | text.len = s.len; 189 | text.str = p = alloc(s.len); 190 | for (i = 0; i < s.len; i++) 191 | *p++ = map[(unsigned char)s.str[i]]; 192 | return text; 193 | } 194 | } 195 | int Text_cmp(T s1, T s2) { 196 | assert(s1.len >= 0 && s1.str); 197 | assert(s2.len >= 0 && s2.str); 198 | if (s1.str == s2.str) 199 | return s1.len - s2.len; 200 | else if (s1.len < s2.len) { 201 | int cond = memcmp(s1.str, s2.str, s1.len); 202 | return cond == 0 ? -1 : cond; 203 | } else if (s1.len > s2.len) { 204 | int cond = memcmp(s1.str, s2.str, s2.len); 205 | return cond == 0 ? +1 : cond; 206 | } else 207 | return memcmp(s1.str, s2.str, s1.len); 208 | } 209 | Text_save_T Text_save(void) { 210 | Text_save_T save; 211 | NEW(save); 212 | save->current = current; 213 | save->avail = current->avail; 214 | alloc(1); 215 | return save; 216 | } 217 | void Text_restore(Text_save_T *save) { 218 | struct chunk *p, *q; 219 | assert(save && *save); 220 | current = (*save)->current; 221 | current->avail = (*save)->avail; 222 | FREE(*save); 223 | for (p = current->link; p; p = q) { 224 | q = p->link; 225 | FREE(p); 226 | } 227 | current->link = NULL; 228 | } 229 | int Text_chr(T s, int i, int j, int c) { 230 | assert(s.len >= 0 && s.str); 231 | i = idx(i, s.len); 232 | j = idx(j, s.len); 233 | if (i > j) { int t = i; i = j; j = t; } 234 | assert(i >= 0 && j <= s.len); 235 | for ( ; i < j; i++) 236 | if (s.str[i] == c) 237 | return i + 1; 238 | return 0; 239 | } 240 | int Text_rchr(T s, int i, int j, int c) { 241 | assert(s.len >= 0 && s.str); 242 | i = idx(i, s.len); 243 | j = idx(j, s.len); 244 | if (i > j) { int t = i; i = j; j = t; } 245 | assert(i >= 0 && j <= s.len); 246 | while (j > i) 247 | if (s.str[--j] == c) 248 | return j + 1; 249 | return 0; 250 | } 251 | int Text_upto(T s, int i, int j, T set) { 252 | assert(set.len >= 0 && set.str); 253 | assert(s.len >= 0 && s.str); 254 | i = idx(i, s.len); 255 | j = idx(j, s.len); 256 | if (i > j) { int t = i; i = j; j = t; } 257 | assert(i >= 0 && j <= s.len); 258 | for ( ; i < j; i++) 259 | if (memchr(set.str, s.str[i], set.len)) 260 | return i + 1; 261 | return 0; 262 | } 263 | int Text_rupto(T s, int i, int j, T set) { 264 | assert(set.len >= 0 && set.str); 265 | assert(s.len >= 0 && s.str); 266 | i = idx(i, s.len); 267 | j = idx(j, s.len); 268 | if (i > j) { int t = i; i = j; j = t; } 269 | assert(i >= 0 && j <= s.len); 270 | while (j > i) 271 | if (memchr(set.str, s.str[--j], set.len)) 272 | return j + 1; 273 | return 0; 274 | } 275 | int Text_find(T s, int i, int j, T str) { 276 | assert(str.len >= 0 && str.str); 277 | assert(s.len >= 0 && s.str); 278 | i = idx(i, s.len); 279 | j = idx(j, s.len); 280 | if (i > j) { int t = i; i = j; j = t; } 281 | assert(i >= 0 && j <= s.len); 282 | if (str.len == 0) 283 | return i + 1; 284 | else if (str.len == 1) { 285 | for ( ; i < j; i++) 286 | if (s.str[i] == *str.str) 287 | return i + 1; 288 | } else 289 | for ( ; i + str.len <= j; i++) 290 | if (equal(s, i, str)) 291 | return i + 1; 292 | return 0; 293 | } 294 | int Text_rfind(T s, int i, int j, T str) { 295 | assert(str.len >= 0 && str.str); 296 | assert(s.len >= 0 && s.str); 297 | i = idx(i, s.len); 298 | j = idx(j, s.len); 299 | if (i > j) { int t = i; i = j; j = t; } 300 | assert(i >= 0 && j <= s.len); 301 | if (str.len == 0) 302 | return j + 1; 303 | else if (str.len == 1) { 304 | while (j > i) 305 | if (s.str[--j] == *str.str) 306 | return j + 1; 307 | } else 308 | for ( ; j - str.len >= i; j--) 309 | if (equal(s, j - str.len, str)) 310 | return j - str.len + 1; 311 | return 0; 312 | } 313 | int Text_any(T s, int i, T set) { 314 | assert(s.len >= 0 && s.str); 315 | assert(set.len >= 0 && set.str); 316 | i = idx(i, s.len); 317 | assert(i >= 0 && i <= s.len); 318 | if (i < s.len && memchr(set.str, s.str[i], set.len)) 319 | return i + 2; 320 | return 0; 321 | } 322 | int Text_many(T s, int i, int j, T set) { 323 | assert(set.len >= 0 && set.str); 324 | assert(s.len >= 0 && s.str); 325 | i = idx(i, s.len); 326 | j = idx(j, s.len); 327 | if (i > j) { int t = i; i = j; j = t; } 328 | assert(i >= 0 && j <= s.len); 329 | if (i < j && memchr(set.str, s.str[i], set.len)) { 330 | do 331 | i++; 332 | while (i < j 333 | && memchr(set.str, s.str[i], set.len)); 334 | return i + 1; 335 | } 336 | return 0; 337 | } 338 | int Text_rmany(T s, int i, int j, T set) { 339 | assert(set.len >= 0 && set.str); 340 | assert(s.len >= 0 && s.str); 341 | i = idx(i, s.len); 342 | j = idx(j, s.len); 343 | if (i > j) { int t = i; i = j; j = t; } 344 | assert(i >= 0 && j <= s.len); 345 | if (j > i && memchr(set.str, s.str[j-1], set.len)) { 346 | do 347 | --j; 348 | while (j >= i 349 | && memchr(set.str, s.str[j], set.len)); 350 | return j + 2; 351 | } 352 | return 0; 353 | } 354 | int Text_match(T s, int i, int j, T str) { 355 | assert(str.len >= 0 && str.str); 356 | assert(s.len >= 0 && s.str); 357 | i = idx(i, s.len); 358 | j = idx(j, s.len); 359 | if (i > j) { int t = i; i = j; j = t; } 360 | assert(i >= 0 && j <= s.len); 361 | if (str.len == 0) 362 | return i + 1; 363 | else if (str.len == 1) { 364 | if (i < j && s.str[i] == *str.str) 365 | return i + 2; 366 | } else if (i + str.len <= j && equal(s, i, str)) 367 | return i + str.len + 1; 368 | return 0; 369 | } 370 | int Text_rmatch(T s, int i, int j, T str) { 371 | assert(str.len >= 0 && str.str); 372 | assert(s.len >= 0 && s.str); 373 | i = idx(i, s.len); 374 | j = idx(j, s.len); 375 | if (i > j) { int t = i; i = j; j = t; } 376 | assert(i >= 0 && j <= s.len); 377 | if (str.len == 0) 378 | return j + 1; 379 | else if (str.len == 1) { 380 | if (j > i && s.str[j-1] == *str.str) 381 | return j; 382 | } else if (j - str.len >= i 383 | && equal(s, j - str.len, str)) 384 | return j - str.len + 1; 385 | return 0; 386 | } 387 | void Text_fmt(int code, va_list_box *box, 388 | int put(int c, void *cl), void *cl, 389 | unsigned char flags[], int width, int precision) { 390 | T *s; 391 | assert(box && flags); 392 | s = va_arg(box->ap, T*); 393 | assert(s && s->len >= 0 && s->str); 394 | Fmt_puts(s->str, s->len, put, cl, flags, 395 | width, precision); 396 | } 397 | -------------------------------------------------------------------------------- /src/thread-nt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "assert.h" 8 | #include "mem.h" 9 | #include "thread.h" 10 | #include "sem.h" 11 | 12 | static char rcsid[] = "$Id$"; 13 | 14 | #define T Thread_T 15 | struct T { 16 | DWORD IDThread; /* Win 32 thread identifier */ 17 | T handle; /* self pointer */ 18 | int code; /* exit code */ 19 | HANDLE join; /* join semaphore */ 20 | T joinlist; /* threads waiting on join */ 21 | T link; /* next thread on this join list */ 22 | T next; /* next thread on this hash chain */ 23 | int alerted; /* 1 if this thread has been alerted */ 24 | int (*apply)(void *); /* initial function for this thread */ 25 | void *args; /* argument for apply */ 26 | }; 27 | 28 | const Except_T Thread_Alerted = { "Thread alerted" }; 29 | const Except_T Thread_Failed = { "Thread creation failed" }; 30 | 31 | static T allthreads[317]; 32 | #define HASH(id) ((int)((id)%(sizeof allthreads/sizeof allthreads[0]))) 33 | static int nthreads; /* number of threads in allthreads */ 34 | static T root; 35 | static HANDLE join0; /* Thread_join(NULL) semaphore */ 36 | static int join0count; /* number of threads waiting on join0; always 0 or 1 */ 37 | 38 | static int critical; 39 | static CRITICAL_SECTION csection; 40 | #define ENTERCRITICAL EnterCriticalSection(&csection); assert(critical == 0); critical++ 41 | #define LEAVECRITICAL critical--; assert(critical == 0); LeaveCriticalSection(&csection) 42 | 43 | static T getThreadByID(DWORD id) { 44 | T t; 45 | 46 | ENTERCRITICAL; 47 | for (t = allthreads[HASH(id)]; t != NULL; t = t->next) 48 | if (t->IDThread == id) 49 | break; 50 | LEAVECRITICAL; 51 | assert(t); 52 | return t; 53 | } 54 | 55 | /* removeThread - must be called from within a critical region */ 56 | static void removeThread(T t) { 57 | T *q; 58 | 59 | q = &allthreads[HASH(t->IDThread)]; 60 | for ( ; *q != NULL && *q != t; q = &(*q)->next) 61 | ; 62 | assert(*q == t); 63 | *q = t->next; 64 | nthreads--; 65 | t->handle = NULL; 66 | } 67 | 68 | static void addThread(T t) { 69 | T *q; 70 | 71 | ENTERCRITICAL; 72 | q = &allthreads[HASH(t->IDThread)]; 73 | t->next = *q; 74 | *q = t; 75 | nthreads++; 76 | t->handle = t; 77 | LEAVECRITICAL; 78 | } 79 | 80 | static void testalert(T t) { 81 | ENTERCRITICAL; 82 | if (t->alerted) { 83 | t->alerted = 0; 84 | LEAVECRITICAL; 85 | RAISE(Thread_Alerted); 86 | } 87 | LEAVECRITICAL; 88 | } 89 | 90 | int Thread_init(int preempt, ...) { 91 | assert(preempt == 0 || preempt == 1); 92 | assert(root == NULL); 93 | TRY 94 | NEW0(root); 95 | EXCEPT(Mem_Failed) 96 | return -1; 97 | END_TRY; 98 | join0 = CreateSemaphore(NULL, 0, 1, NULL); 99 | if (join0 == NULL) 100 | return -1; 101 | root->join = CreateSemaphore(NULL, 0, INT_MAX, NULL); 102 | if (root->join == NULL) { 103 | BOOL result = CloseHandle(join0); 104 | assert(result == TRUE); 105 | return -1; 106 | } 107 | InitializeCriticalSection(&csection); 108 | root->IDThread = GetCurrentThreadId(); 109 | addThread(root); 110 | /* handle preempt == 0 */ 111 | return 1; 112 | } 113 | 114 | T Thread_self(void) { 115 | assert(root); 116 | return getThreadByID(GetCurrentThreadId()); 117 | } 118 | 119 | void Thread_pause(void) { 120 | assert(root); 121 | Sleep(0); 122 | } 123 | 124 | int Thread_join(T t) { 125 | T current = Thread_self(); 126 | 127 | assert(root); 128 | assert(t != current); 129 | testalert(current); 130 | if (t != NULL) { 131 | ENTERCRITICAL; 132 | if (t->handle == t) { 133 | HANDLE join = t->join; 134 | DWORD result; 135 | assert(current->link == NULL); 136 | current->link = t->joinlist; 137 | t->joinlist = current; 138 | LEAVECRITICAL; 139 | result = WaitForSingleObject(join, INFINITE); 140 | assert(result != WAIT_FAILED); 141 | testalert(current); 142 | return current->code; 143 | } else { 144 | LEAVECRITICAL; 145 | return -1; 146 | } 147 | } 148 | ENTERCRITICAL; 149 | if (nthreads > 1) { 150 | DWORD result; 151 | assert(join0count == 0); 152 | join0count++; 153 | LEAVECRITICAL; 154 | result = WaitForSingleObject(join0, INFINITE); 155 | assert(result != WAIT_FAILED); 156 | ENTERCRITICAL; 157 | join0count--; 158 | LEAVECRITICAL; 159 | testalert(current); 160 | } else { 161 | assert(join0count == 0); 162 | LEAVECRITICAL; 163 | return 0; 164 | } 165 | } 166 | 167 | void Thread_exit(int code) { 168 | BOOL result; 169 | T current = Thread_self(); 170 | 171 | ENTERCRITICAL; 172 | removeThread(current); 173 | if (current->joinlist != NULL) { 174 | T t, n; 175 | int count = 0; 176 | assert(current->join); 177 | for (t = current->joinlist; t != NULL; t = n) { 178 | t->code = code; 179 | n = t->link; 180 | t->link = NULL; 181 | count++; 182 | } 183 | current->joinlist = NULL; 184 | result = ReleaseSemaphore(current->join, count, NULL); 185 | assert(result == TRUE); 186 | } 187 | result = CloseHandle(current->join); 188 | assert(result == TRUE); 189 | current->join = NULL; 190 | if (join0count > 0 && nthreads == 1) { 191 | assert(join0count == 1); 192 | result = ReleaseSemaphore(join0, 1, NULL); 193 | assert(result == TRUE); 194 | } 195 | if (nthreads == 0) { 196 | result = CloseHandle(join0); 197 | assert(result == TRUE); 198 | } 199 | FREE(current); 200 | LEAVECRITICAL; 201 | _endthreadex(code); 202 | } 203 | 204 | void Thread_alert(T t) { 205 | assert(root); 206 | ENTERCRITICAL; 207 | assert(t && t->handle == t); 208 | t->alerted = 1; 209 | LEAVECRITICAL; 210 | } 211 | 212 | static unsigned __stdcall start(void *p) { 213 | T t = p; 214 | 215 | if (Except_index == -1) 216 | Except_init(); 217 | TlsSetValue(Except_index, NULL); 218 | Thread_exit((*t->apply)(t->args)); 219 | return 0; 220 | } 221 | 222 | T Thread_new(int apply(void *), void *args, int nbytes, ...) { 223 | T t; 224 | HANDLE hThread; 225 | 226 | assert(root); 227 | assert(apply); 228 | assert(args && nbytes >= 0 || args == NULL); 229 | if (args == NULL) 230 | nbytes = 0; 231 | TRY 232 | t = ALLOC((sizeof (*t) + nbytes + 15)&~15); 233 | memset(t, '\0', sizeof *t); 234 | EXCEPT(Mem_Failed) 235 | RAISE(Thread_Failed); 236 | END_TRY; 237 | t->join = CreateSemaphore(NULL, 0, INT_MAX, NULL); 238 | if (t->join == NULL) { 239 | FREE(t); 240 | RAISE(Thread_Failed); 241 | } 242 | if (nbytes > 0) { 243 | t->args = t + 1; 244 | memcpy(t->args, args, nbytes); 245 | } else 246 | t->args = args; 247 | t->apply = apply; 248 | hThread = (HANDLE)_beginthreadex( 249 | NULL, /* default security attributes */ 250 | 0, /* default stack size */ 251 | start, /* initial function */ 252 | t, /* start's argument */ 253 | 0, /* default thread creation flags */ 254 | &t->IDThread /* where to store the thread id */ 255 | ); 256 | if (hThread == NULL) { 257 | CloseHandle(t->join); 258 | FREE(t); 259 | RAISE(Thread_Failed); 260 | } 261 | CloseHandle(hThread); 262 | addThread(t); 263 | return t; 264 | } 265 | #undef T 266 | 267 | #define T Sem_T 268 | T *Sem_new(int count) { 269 | T *s; 270 | 271 | NEW(s); 272 | Sem_init(s, count); 273 | return s; 274 | } 275 | 276 | void Sem_init(T *s, int count) { 277 | assert(root); 278 | assert(s); 279 | assert(count >= 0); 280 | s->count = 0; 281 | s->queue = CreateSemaphore(NULL, count, INT_MAX, NULL); 282 | assert(s->queue); 283 | } 284 | 285 | void Sem_wait(T *s) { 286 | DWORD result; 287 | Thread_T current = Thread_self(); 288 | 289 | assert(s); 290 | testalert(current); 291 | result = WaitForSingleObject(s->queue, INFINITE); 292 | assert(result != WAIT_FAILED); 293 | ENTERCRITICAL; 294 | if (current->alerted) { 295 | BOOL result; 296 | current->alerted = 0; 297 | LEAVECRITICAL; 298 | result = ReleaseSemaphore(s->queue, 1, NULL); 299 | assert(result == TRUE); 300 | RAISE(Thread_Alerted); 301 | } 302 | LEAVECRITICAL; 303 | } 304 | 305 | void Sem_signal(T *s) { 306 | BOOL result; 307 | 308 | assert(root); 309 | assert(s); 310 | result = ReleaseSemaphore(s->queue, 1, NULL); 311 | assert(result == TRUE); 312 | } 313 | #undef T 314 | -------------------------------------------------------------------------------- /src/thread.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "assert.h" 8 | #include "mem.h" 9 | #include "thread.h" 10 | #include "sem.h" 11 | void _MONITOR(void) {} 12 | extern void _ENDMONITOR(void); 13 | #define T Thread_T 14 | #define isempty(q) ((q) == NULL) 15 | struct T { 16 | unsigned long *sp; /* must be first */ 17 | T link; 18 | T *inqueue; 19 | T handle; 20 | Except_Frame *estack; 21 | int code; 22 | T join; 23 | T next; 24 | int alerted; 25 | }; 26 | static T ready = NULL; 27 | static T current; 28 | static int nthreads; 29 | static struct Thread_T root; 30 | static T join0; 31 | static T freelist; 32 | const Except_T Thread_Alerted = { "Thread alerted" }; 33 | const Except_T Thread_Failed = 34 | { "Thread creation failed" }; 35 | static int critical; 36 | extern void _swtch(T from, T to); 37 | static void put(T t, T *q) { 38 | assert(t); 39 | assert(t->inqueue == NULL && t->link == NULL); 40 | if (*q) { 41 | t->link = (*q)->link; 42 | (*q)->link = t; 43 | } else 44 | t->link = t; 45 | *q = t; 46 | t->inqueue = q; 47 | } 48 | static T get(T *q) { 49 | T t; 50 | assert(!isempty(*q)); 51 | t = (*q)->link; 52 | if (t == *q) 53 | *q = NULL; 54 | else 55 | (*q)->link = t->link; 56 | assert(t->inqueue == q); 57 | t->link = NULL; 58 | t->inqueue = NULL; 59 | return t; 60 | } 61 | static void delete(T t, T *q) { 62 | T p; 63 | assert(t->link && t->inqueue == q); 64 | assert(!isempty(*q)); 65 | for (p = *q; p->link != t; p = p->link) 66 | ; 67 | if (p == t) 68 | *q = NULL; 69 | else { 70 | p->link = t->link; 71 | if (*q == t) 72 | *q = p; 73 | } 74 | t->link = NULL; 75 | t->inqueue = NULL; 76 | } 77 | static void run(void) { 78 | T t = current; 79 | current = get(&ready); 80 | t->estack = Except_stack; 81 | Except_stack = current->estack; 82 | _swtch(t, current); 83 | } 84 | static void testalert(void) { 85 | if (current->alerted) { 86 | current->alerted = 0; 87 | RAISE(Thread_Alerted); 88 | } 89 | } 90 | static void release(void) { 91 | T t; 92 | do { critical++; 93 | while ((t = freelist) != NULL) { 94 | freelist = t->next; 95 | FREE(t); 96 | } 97 | critical--; } while (0); 98 | } 99 | #if linux 100 | #include 101 | static int interrupt(int sig, struct sigcontext sc) { 102 | if (critical || 103 | sc.eip >= (unsigned long)_MONITOR 104 | && sc.eip <= (unsigned long)_ENDMONITOR) 105 | return 0; 106 | put(current, &ready); 107 | do { critical++; 108 | sigsetmask(sc.oldmask); 109 | critical--; } while (0); 110 | run(); 111 | return 0; 112 | } 113 | #else 114 | #if __APPLE__ 115 | #define sc_pc sc_eip 116 | #endif 117 | static int interrupt(int sig, int code, 118 | struct sigcontext *scp) { 119 | if (critical || 120 | scp->sc_pc >= (unsigned long)_MONITOR 121 | && scp->sc_pc <= (unsigned long)_ENDMONITOR) 122 | return 0; 123 | put(current, &ready); 124 | do { critical++; 125 | sigsetmask(scp->sc_mask); 126 | critical--; } while (0); 127 | run(); 128 | return 0; 129 | } 130 | #endif 131 | int Thread_init(int preempt, ...) { 132 | assert(preempt == 0 || preempt == 1); 133 | assert(current == NULL); 134 | root.handle = &root; 135 | current = &root; 136 | nthreads = 1; 137 | if (preempt) { 138 | { 139 | struct sigaction sa; 140 | memset(&sa, '\0', sizeof sa); 141 | sa.sa_handler = (void (*)())interrupt; 142 | if (sigaction(SIGVTALRM, &sa, NULL) < 0) 143 | return 0; 144 | } 145 | { 146 | struct itimerval it; 147 | it.it_value.tv_sec = 0; 148 | it.it_value.tv_usec = 10; 149 | it.it_interval.tv_sec = 0; 150 | it.it_interval.tv_usec = 10; 151 | if (setitimer(ITIMER_VIRTUAL, &it, NULL) < 0) 152 | return 0; 153 | } 154 | } 155 | return 1; 156 | } 157 | T Thread_self(void) { 158 | assert(current); 159 | return current; 160 | } 161 | void Thread_pause(void) { 162 | assert(current); 163 | put(current, &ready); 164 | run(); 165 | } 166 | int Thread_join(T t) { 167 | assert(current && t != current); 168 | testalert(); 169 | if (t) { 170 | if (t->handle == t) { 171 | put(current, &t->join); 172 | run(); 173 | testalert(); 174 | return current->code; 175 | } else 176 | return -1; 177 | } else { 178 | assert(isempty(join0)); 179 | if (nthreads > 1) { 180 | put(current, &join0); 181 | run(); 182 | testalert(); 183 | } 184 | return 0; 185 | } 186 | } 187 | void Thread_exit(int code) { 188 | assert(current); 189 | release(); 190 | if (current != &root) { 191 | current->next = freelist; 192 | freelist = current; 193 | } 194 | current->handle = NULL; 195 | while (!isempty(current->join)) { 196 | T t = get(¤t->join); 197 | t->code = code; 198 | put(t, &ready); 199 | } 200 | if (!isempty(join0) && nthreads == 2) { 201 | assert(isempty(ready)); 202 | put(get(&join0), &ready); 203 | } 204 | if (--nthreads == 0) 205 | exit(code); 206 | else 207 | run(); 208 | } 209 | void Thread_alert(T t) { 210 | assert(current); 211 | assert(t && t->handle == t); 212 | t->alerted = 1; 213 | if (t->inqueue) { 214 | delete(t, t->inqueue); 215 | put(t, &ready); 216 | } 217 | } 218 | T Thread_new(int apply(void *), void *args, 219 | int nbytes, ...) { 220 | T t; 221 | assert(current); 222 | assert(apply); 223 | assert(args && nbytes >= 0 || args == NULL); 224 | if (args == NULL) 225 | nbytes = 0; 226 | { 227 | int stacksize = (16*1024+sizeof (*t)+nbytes+15)&~15; 228 | release(); 229 | do { critical++; 230 | TRY 231 | t = ALLOC(stacksize); 232 | memset(t, '\0', sizeof *t); 233 | EXCEPT(Mem_Failed) 234 | t = NULL; 235 | END_TRY; 236 | critical--; } while (0); 237 | if (t == NULL) 238 | RAISE(Thread_Failed); 239 | t->sp = (void *)(((unsigned long)t + stacksize)&~15U); 240 | } 241 | t->handle = t; 242 | if (nbytes > 0) { 243 | t->sp -= ((nbytes + 15U)&~15)/sizeof (*t->sp); 244 | do { critical++; 245 | memcpy(t->sp, args, nbytes); 246 | critical--; } while (0); 247 | args = t->sp; 248 | } 249 | #if alpha 250 | { extern void _start(void); 251 | t->sp -= 112/8; 252 | t->sp[(48+24)/8] = (unsigned long)Thread_exit; 253 | t->sp[(48+16)/8] = (unsigned long)args; 254 | t->sp[(48+ 8)/8] = (unsigned long)apply; 255 | t->sp[(48+ 0)/8] = (unsigned long)_start; } 256 | #elif mips 257 | { extern void _start(void); 258 | t->sp -= 16/4; 259 | t->sp -= 88/4; 260 | t->sp[(48+20)/4] = (unsigned long)Thread_exit; 261 | t->sp[(48+28)/4] = (unsigned long)args; 262 | t->sp[(48+32)/4] = (unsigned long)apply; 263 | t->sp[(48+36)/4] = (unsigned long)_start; } 264 | #elif sparc 265 | { int i; void *fp; extern void _start(void); 266 | for (i = 0; i < 8; i++) 267 | *--t->sp = 0; 268 | *--t->sp = (unsigned long)args; 269 | *--t->sp = (unsigned long)apply; 270 | t->sp -= 64/4; 271 | fp = t->sp; 272 | *--t->sp = (unsigned long)_start - 8; 273 | *--t->sp = (unsigned long)fp; 274 | t->sp -= 64/4; } 275 | #elif (linux || __APPLE__) && i386 276 | { extern void _thrstart(void); 277 | t->sp -= 16/4; /* keep stack aligned to 16-byte boundaries */ 278 | *t->sp = (unsigned long)_thrstart; 279 | t->sp -= 16/4; 280 | t->sp[4/4] = (unsigned long)apply; 281 | t->sp[8/4] = (unsigned long)args; 282 | t->sp[12/4] = (unsigned long)t->sp + (4+16)/4; } 283 | #else 284 | Unsupported platform 285 | #endif 286 | nthreads++; 287 | put(t, &ready); 288 | return t; 289 | } 290 | #undef T 291 | #define T Sem_T 292 | T *Sem_new(int count) { 293 | T *s; 294 | NEW(s); 295 | Sem_init(s, count); 296 | return s; 297 | } 298 | void Sem_init(T *s, int count) { 299 | assert(current); 300 | assert(s); 301 | s->count = count; 302 | s->queue = NULL; 303 | } 304 | void Sem_wait(T *s) { 305 | assert(current); 306 | assert(s); 307 | testalert(); 308 | if (s->count <= 0) { 309 | put(current, (Thread_T *)&s->queue); 310 | run(); 311 | testalert(); 312 | } else 313 | --s->count; 314 | } 315 | void Sem_signal(T *s) { 316 | assert(current); 317 | assert(s); 318 | if (s->count == 0 && !isempty(s->queue)) { 319 | Thread_T t = get((Thread_T *)&s->queue); 320 | assert(!t->alerted); 321 | put(t, &ready); 322 | } else 323 | ++s->count; 324 | } 325 | #undef T 326 | -------------------------------------------------------------------------------- /src/xp.c: -------------------------------------------------------------------------------- 1 | static char rcsid[] = "$Id$"; 2 | #include 3 | #include 4 | #include "assert.h" 5 | #include "xp.h" 6 | #define T XP_T 7 | #define BASE (1<<8) 8 | static char map[] = { 9 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 | 36, 36, 36, 36, 36, 36, 36, 11 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 12 | 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 13 | 36, 36, 36, 36, 36, 36, 14 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 15 | 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 16 | }; 17 | unsigned long XP_fromint(int n, T z, unsigned long u) { 18 | int i = 0; 19 | do 20 | z[i++] = u%BASE; 21 | while ((u /= BASE) > 0 && i < n); 22 | for ( ; i < n; i++) 23 | z[i] = 0; 24 | return u; 25 | } 26 | unsigned long XP_toint(int n, T x) { 27 | unsigned long u = 0; 28 | int i = (int)sizeof u; 29 | if (i > n) 30 | i = n; 31 | while (--i >= 0) 32 | u = BASE*u + x[i]; 33 | return u; 34 | } 35 | int XP_length(int n, T x) { 36 | while (n > 1 && x[n-1] == 0) 37 | n--; 38 | return n; 39 | } 40 | int XP_add(int n, T z, T x, T y, int carry) { 41 | int i; 42 | for (i = 0; i < n; i++) { 43 | carry += x[i] + y[i]; 44 | z[i] = carry%BASE; 45 | carry /= BASE; 46 | } 47 | return carry; 48 | } 49 | int XP_sub(int n, T z, T x, T y, int borrow) { 50 | int i; 51 | for (i = 0; i < n; i++) { 52 | int d = (x[i] + BASE) - borrow - y[i]; 53 | z[i] = d%BASE; 54 | borrow = 1 - d/BASE; 55 | } 56 | return borrow; 57 | } 58 | int XP_sum(int n, T z, T x, int y) { 59 | int i; 60 | for (i = 0; i < n; i++) { 61 | y += x[i]; 62 | z[i] = y%BASE; 63 | y /= BASE; 64 | } 65 | return y; 66 | } 67 | int XP_diff(int n, T z, T x, int y) { 68 | int i; 69 | for (i = 0; i < n; i++) { 70 | int d = (x[i] + BASE) - y; 71 | z[i] = d%BASE; 72 | y = 1 - d/BASE; 73 | } 74 | return y; 75 | } 76 | int XP_neg(int n, T z, T x, int carry) { 77 | int i; 78 | for (i = 0; i < n; i++) { 79 | carry += (unsigned char)~x[i]; 80 | z[i] = carry%BASE; 81 | carry /= BASE; 82 | } 83 | return carry; 84 | } 85 | int XP_mul(T z, int n, T x, int m, T y) { 86 | int i, j, carryout = 0; 87 | for (i = 0; i < n; i++) { 88 | unsigned carry = 0; 89 | for (j = 0; j < m; j++) { 90 | carry += x[i]*y[j] + z[i+j]; 91 | z[i+j] = carry%BASE; 92 | carry /= BASE; 93 | } 94 | for ( ; j < n + m - i; j++) { 95 | carry += z[i+j]; 96 | z[i+j] = carry%BASE; 97 | carry /= BASE; 98 | } 99 | carryout |= carry; 100 | } 101 | return carryout; 102 | } 103 | int XP_product(int n, T z, T x, int y) { 104 | int i; 105 | unsigned carry = 0; 106 | for (i = 0; i < n; i++) { 107 | carry += x[i]*y; 108 | z[i] = carry%BASE; 109 | carry /= BASE; 110 | } 111 | return carry; 112 | } 113 | int XP_div(int n, T q, T x, int m, T y, T r, T tmp) { 114 | int nx = n, my = m; 115 | n = XP_length(n, x); 116 | m = XP_length(m, y); 117 | if (m == 1) { 118 | if (y[0] == 0) 119 | return 0; 120 | r[0] = XP_quotient(nx, q, x, y[0]); 121 | memset(r + 1, '\0', my - 1); 122 | } else if (m > n) { 123 | memset(q, '\0', nx); 124 | memcpy(r, x, n); 125 | memset(r + n, '\0', my - n); 126 | } else { 127 | int k; 128 | unsigned char *rem = tmp, *dq = tmp + n + 1; 129 | assert(2 <= m && m <= n); 130 | memcpy(rem, x, n); 131 | rem[n] = 0; 132 | for (k = n - m; k >= 0; k--) { 133 | int qk; 134 | { 135 | int i; 136 | assert(2 <= m && m <= k+m && k+m <= n); 137 | { 138 | int km = k + m; 139 | unsigned long y2 = y[m-1]*BASE + y[m-2]; 140 | unsigned long r3 = rem[km]*(BASE*BASE) + 141 | rem[km-1]*BASE + rem[km-2]; 142 | qk = r3/y2; 143 | if (qk >= BASE) 144 | qk = BASE - 1; 145 | } 146 | dq[m] = XP_product(m, dq, y, qk); 147 | for (i = m; i > 0; i--) 148 | if (rem[i+k] != dq[i]) 149 | break; 150 | if (rem[i+k] < dq[i]) 151 | dq[m] = XP_product(m, dq, y, --qk); 152 | } 153 | q[k] = qk; 154 | { 155 | int borrow; 156 | assert(0 <= k && k <= k+m); 157 | borrow = XP_sub(m + 1, &rem[k], &rem[k], dq, 0); 158 | assert(borrow == 0); 159 | } 160 | } 161 | memcpy(r, rem, m); 162 | { 163 | int i; 164 | for (i = n-m+1; i < nx; i++) 165 | q[i] = 0; 166 | for (i = m; i < my; i++) 167 | r[i] = 0; 168 | } 169 | } 170 | return 1; 171 | } 172 | int XP_quotient(int n, T z, T x, int y) { 173 | int i; 174 | unsigned carry = 0; 175 | for (i = n - 1; i >= 0; i--) { 176 | carry = carry*BASE + x[i]; 177 | z[i] = carry/y; 178 | carry %= y; 179 | } 180 | return carry; 181 | } 182 | int XP_cmp(int n, T x, T y) { 183 | int i = n - 1; 184 | while (i > 0 && x[i] == y[i]) 185 | i--; 186 | return x[i] - y[i]; 187 | } 188 | void XP_lshift(int n, T z, int m, T x, int s, int fill) { 189 | fill = fill ? 0xFF : 0; 190 | { 191 | int i, j = n - 1; 192 | if (n > m) 193 | i = m - 1; 194 | else 195 | i = n - s/8 - 1; 196 | for ( ; j >= m + s/8; j--) 197 | z[j] = 0; 198 | for ( ; i >= 0; i--, j--) 199 | z[j] = x[i]; 200 | for ( ; j >= 0; j--) 201 | z[j] = fill; 202 | } 203 | s %= 8; 204 | if (s > 0) 205 | { 206 | XP_product(n, z, z, 1<>(8-s); 208 | } 209 | } 210 | void XP_rshift(int n, T z, int m, T x, int s, int fill) { 211 | fill = fill ? 0xFF : 0; 212 | { 213 | int i, j = 0; 214 | for (i = s/8; i < m && j < n; i++, j++) 215 | z[j] = x[i]; 216 | for ( ; j < n; j++) 217 | z[j] = fill; 218 | } 219 | s %= 8; 220 | if (s > 0) 221 | { 222 | XP_quotient(n, z, z, 1<= 2 && base <= 36); 231 | while (*p && isspace(*p)) 232 | p++; 233 | if ((*p && isalnum(*p) && map[*p-'0'] < base)) { 234 | int carry; 235 | for ( ; (*p && isalnum(*p) && map[*p-'0'] < base); p++) { 236 | carry = XP_product(n, z, z, base); 237 | if (carry) 238 | break; 239 | XP_sum(n, z, z, map[*p-'0']); 240 | } 241 | if (end) 242 | *end = (char *)p; 243 | return carry; 244 | } else { 245 | if (end) 246 | *end = (char *)str; 247 | return 0; 248 | } 249 | } 250 | char *XP_tostr(char *str, int size, int base, 251 | int n, T x) { 252 | int i = 0; 253 | assert(str); 254 | assert(base >= 2 && base <= 36); 255 | do { 256 | int r = XP_quotient(n, x, x, base); 257 | assert(i < size); 258 | str[i++] = 259 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[r]; 260 | while (n > 1 && x[n-1] == 0) 261 | n--; 262 | } while (n > 1 || x[0] != 0); 263 | assert(i < size); 264 | str[i] = '\0'; 265 | { 266 | int j; 267 | for (j = 0; j < --i; j++) { 268 | char c = str[j]; 269 | str[j] = str[i]; 270 | str[i] = c; 271 | } 272 | } 273 | return str; 274 | } 275 | --------------------------------------------------------------------------------