zoukankan      html  css  js  c++  java
  • 读书笔记之:C语言接口与实现[+]

    第1章 简介

    1. literate程序

    2. 宏指令与条件编译指令

    第2章 接口与实现

    1. 接口与实现的关系

    2. Arith接口及实现:

    arith.h:

    View Code
    /* $Id: H:/drh/idioms/book/RCS/inter.doc,v 1.11 1997/02/21 19:42:15 drh Exp $ */
    extern int Arith_max(int x, int y);
    extern int Arith_min(int x, int y);
    extern int Arith_div(int x, int y);
    extern int Arith_mod(int x, int y);
    extern int Arith_ceiling(int x, int y);
    extern int Arith_floor  (int x, int y);

    arith.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/inter.doc,v 1.11 1997/02/21 19:42:15 drh Exp $";
    #include "arith.h"
    int Arith_max(int x, int y) {
        return x > y ? x : y;
    }
    int Arith_min(int x, int y) {
        return x > y ? y : x;
    }
    int Arith_div(int x, int y) {
        if (-13/5 == -2
        &&    (x < 0) != (y < 0) && x%y != 0)
            return x/y - 1;
        else
            return x/y;
    }
    int Arith_mod(int x, int y) {
        if (-13/5 == -2
        &&    (x < 0) != (y < 0) && x%y != 0)
            return x%y + y;
        else
            return x%y;
    }
    int Arith_floor(int x, int y) {
        return Arith_div(x, y);
    }
    int Arith_ceiling(int x, int y) {
        return Arith_div(x, y) + (x%y != 0);
    }

    3. 抽象数据类型Stack

    4. 客户调用程序的责任

    stack.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/inter.doc,v 1.11 1997/02/21 19:42:15 drh Exp $ */
    #ifndef STACK_INCLUDED
    #define STACK_INCLUDED
    #define T Stack_T
    typedef struct T *T;
    extern T     Stack_new  (void);
    extern int   Stack_empty(T stk);
    extern void  Stack_push (T stk, void *x);
    extern void *Stack_pop  (T stk);
    extern void  Stack_free (T *stk);
    #undef T
    #endif

    stack.c 

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/inter.doc,v 1.11 1997/02/21 19:42:15 drh Exp $";
    #include <stddef.h>
    #include "assert.h"
    #include "mem.h"
    #include "stack.h"
    #define T Stack_T
    struct T {
        int count;
        struct elem {
            void *x;
            struct elem *link;
        } *head;
    };
    T Stack_new(void) {
        T stk;
        NEW(stk);
        stk->count = 0;
        stk->head = NULL;
        return stk;
    }
    int Stack_empty(T stk) {
        assert(stk);
        return stk->count == 0;
    }
    void Stack_push(T stk, void *x) {
        struct elem *t;
        assert(stk);
        NEW(t);
        t->x = x;
        t->link = stk->head;
        stk->head = t;
        stk->count++;
    }
    void *Stack_pop(T stk) {
        void *x;
        struct elem *t;
        assert(stk);
        assert(stk->count > 0);
        t = stk->head;
        stk->head = t->link;
        stk->count--;
        x = t->x;
        FREE(t);
        return x;
    }
    void Stack_free(T *stk) {
        struct elem *t, *u;
        assert(stk && *stk);
        for (t = (*stk)->head; t; t = u) {
            u = t->link;
            FREE(t);
        }
        FREE(*stk);
    }

    第3章 原子

    1. 接口

    atom.h: 

    View Code
    /* $Id: H:/drh/idioms/book/RCS/atom.doc,v 1.10 1997/02/21 19:42:46 drh Exp $ */
    #ifndef ATOM_INCLUDED
    #define ATOM_INCLUDED
    extern       int   Atom_length(const char *str);
    extern const char *Atom_new   (const char *str, int len);
    extern const char *Atom_string(const char *str);
    extern const char *Atom_int   (long n);
    #endif

    atom.c:

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/atom.doc,v 1.10 1997/02/21 19:42:46 drh Exp $";
    #include "atom.h"
    #include <string.h>
    #include "assert.h"
    #include <limits.h>
    #include "mem.h"
    #define NELEMS(x) ((sizeof (x))/(sizeof ((x)[0])))
    static struct atom {
        struct atom *link;
        int len;
        char *str;
    } *buckets[2048];
    static unsigned long scatter[] = {
    2078917053143302914102710082719532103027552536312002600785,
    14053902304524801110999515674338323502018585307438263339,
    8135289291703199216618906479573714703766270699275680090,
    151032044015835839261723401032196544332910981836821636505764,
    980071615101159796164327927313154612751575840381069844923,
    471560540890174431213147837149866136820422277461968401469,
    13537785051300134328201364948030624642417339666781884751139,
    7445097634000119591440466707136341624297372666359253759,
    163909633233656345516428376851215013716154523136593537720,
    7040358321134594751160513568113473151063025723791762719719,
    269676381774132919185173716314828242191253106391746481261,
    1303742040147908914489913194111699078721785335569485614972,
    90717536438236168488562693120015842317457779271859353594,
    2594121821237390611484334011902249868304920680202956538,
    3483039401008956512133755128919534396212087879701640123668,
    156867569347846435226677294012729292081961288571392083579,
    8719268211117546963187117272417710587621399711871509024645,
    1091900861047146551189138632999481701812473049751489680608,
    70668696415067171575795875727551203661261483377884508252,
    9580769041609787317189346476414814454514157432912102252735,
    178826821483693533643323343920550411542109864544247038362,
    2996410858343077171364585325233301614578828311504556512,
    1532354806567072918404219416127625748815618899361651524391,
    61845444812109325210107579001198042020876213618124757630,
    208255027218342905221734544947182853138919824350681002804590,
    1783300476162321963418397399266905026715307771401802120822,
    316088629183041822548894489116806739541853748387946827723,
    1037746818123861954515139006411441966234367393385928306929,
    94600697798584783410494001811956764878364062061925613800,
    208152250821189564791612420674166858380718000042201447372094,
    52390475014358210489231080802161610281504871315306401572,
    20182818511820959944213681979835974309413541502501843084537,
    130657081724441342093422043467298781016863796551301613820,
    1601294739484902984139978006503211273294184214176384212,
    281341425228223074147857043189376209918968068821947861263,
    119365054627322798412361986632116758626489389012593586330,
    2756765513601872152670626262650127017199303101621212876,
    2108097238202650112718656262978948340245520052901404522304,
    489641965816381188942528818894220250902765436125855,
    36532641579036907926434892951318345853664753113672163,
    313561074173029807728690014715497597371699573055776289160,
    214334606819752496061136476375262925046927786591856406685,
    18841379235339224917354241651602280572
    };
    const char *Atom_string(const char *str) {
        assert(str);
        return Atom_new(str, strlen(str));
    }
    const char *Atom_int(long n) {
        char str[43];
        char *s = str + sizeof str;
        unsigned long m;
        if (n == LONG_MIN)
            m = LONG_MAX + 1UL;
        else if (n < 0)
            m = -n;
        else
            m = n;
        do
            *--s = m%10 + '0';
        while ((m /= 10) > 0);
        if (n < 0)
            *--s = '-';
        return Atom_new(s, (str + sizeof str) - s);
    }
    const char *Atom_new(const char *str, int len) {
        unsigned long h;
        int i;
        struct atom *p;
        assert(str);
        assert(len >= 0);
        for (h = 0, i = 0; i < len; i++)
            h = (h<<1) + scatter[(unsigned char)str[i]];
        h &= NELEMS(buckets)-1;
        for (p = buckets[h]; p; p = p->link)
            if (len == p->len) {
                for (i = 0; i < len && p->str[i] == str[i]; )
                    i++;
                if (i == len)
                    return p->str;
            }
        p = ALLOC(sizeof (*p) + len + 1);
        p->len = len;
        p->str = (char *)(p + 1);
        if (len > 0)
            memcpy(p->str, str, len);
        p->str[len] = '\0';
        p->link = buckets[h];
        buckets[h] = p;
        return p->str;
    }
    int Atom_length(const char *str) {
        struct atom *p;
        int i;
        assert(str);
        for (i = 0; i < NELEMS(buckets); i++)
            for (p = buckets[i]; p; p = p->link)
                if (p->str == str)
                    return p->len;
        assert(0);
        return 0;
    }

    第4章 异常与断言

    except.h 

    View Code
    /* $Id: H:/drh/idioms/book/RCS/except.doc,v 1.10 1997/02/21 19:43:55 drh Exp $ */
    #ifndef EXCEPT_INCLUDED
    #define EXCEPT_INCLUDED
    #include <setjmp.h>
    #define T Except_T
    typedef struct T {
        char *reason;
    } T;
    typedef struct Except_Frame Except_Frame;
    struct Except_Frame {
        Except_Frame *prev;
        jmp_buf env;
        const char *file;
        int line;
        const T *exception;
    };
    enum { Except_entered=0, Except_raised,
           Except_handled,   Except_finalized };
    #ifdef WIN32
    __declspec(thread)
    #endif
    extern Except_Frame *Except_stack;
    extern const Except_T Assert_Failed;
    void Except_raise(const T *e, const char *file,int line);
    #define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
    #define RERAISE Except_raise(Except_frame.exception, \
        Except_frame.file, Except_frame.line)
    #define RETURN switch (Except_stack = Except_stack->prev,0) default: return
    #define TRY do { \
        volatile int Except_flag; \
        Except_Frame Except_frame; \
        Except_frame.prev = Except_stack; \
        Except_stack = &Except_frame;  \
        Except_flag = setjmp(Except_frame.env); \
        if (Except_flag == Except_entered) {
    #define EXCEPT(e) \
            if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
        } else if (Except_frame.exception == &(e)) { \
            Except_flag = Except_handled;
    #define ELSE \
            if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
        } else { \
            Except_flag = Except_handled;
    #define FINALLY \
            if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
        } { \
            if (Except_flag == Except_entered) \
                Except_flag = Except_finalized;
    #define END_TRY \
            if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
            } if (Except_flag == Except_raised) RERAISE; \
    while (0)
    #undef T
    #endif

    except.c 

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/except.doc,v 1.10 1997/02/21 19:43:55 drh Exp $";
    #include <stdlib.h>
    #include <stdio.h>
    #include "assert.h"
    #include "except.h"
    #define T Except_T
    #ifdef WIN32
    __declspec(thread)
    #endif
    Except_Frame *Except_stack = NULL;
    void Except_raise(const T *e, const char *file,
        int line) {
        Except_Frame *p = Except_stack;
        assert(e);
        if (p == NULL) {
            fprintf(stderr, "Uncaught exception");
            if (e->reason)
                fprintf(stderr, " %s", e->reason);
            else
                fprintf(stderr, " at 0x%p", e);
            if (file && line > 0)
                fprintf(stderr, " raised at %s:%d\n", file, line);
            fprintf(stderr, "aborting...\n");
            fflush(stderr);
            abort();
        }
        p->exception = e;
        p->file = file;
        p->line = line;
        Except_stack = Except_stack->prev;
        longjmp(p->env, Except_raised);
    }

    assert.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/except.doc,v 1.10 1997/02/21 19:43:55 drh Exp $ */
    #undef assert
    #ifdef NDEBUG
    #define assert(e) ((void)0)
    #else
    #include "except.h"
    extern void assert(int e);
    #define assert(e) ((void)((e)||(RAISE(Assert_Failed),0)))
    #endif

    assert.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/except.doc,v 1.10 1997/02/21 19:43:55 drh Exp $";
    #include "assert.h"
    const Except_T Assert_Failed = { "Assertion failed" };
    void (assert)(int e) {
        assert(e);
    }

     

    第5章 内存管理

    MEM分配接口

    mem.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/mem.doc,v 1.12 1997/10/27 23:08:05 drh Exp $ */
    #ifndef MEM_INCLUDED
    #define MEM_INCLUDED
    #include "except.h"
    extern const Except_T Mem_Failed;
    extern void *Mem_alloc (long nbytes,
        const char *file, int line);
    extern void *Mem_calloc(long count, long nbytes,
        const char *file, int line);
    extern void Mem_free(void *ptr,
        const char *file, int line);
    extern void *Mem_resize(void *ptr, long nbytes,
        const char *file, int line);
    #define ALLOC(nbytes) \
        Mem_alloc((nbytes), __FILE__, __LINE__)
    #define CALLOC(count, nbytes) \
        Mem_calloc((count), (nbytes), __FILE__, __LINE__)
    #define  NEW(p) ((p) = ALLOC((long)sizeof *(p)))
    #define NEW0(p) ((p) = CALLOC(1, (long)sizeof *(p)))
    #define FREE(ptr) ((void)(Mem_free((ptr), \
        __FILE__, __LINE__), (ptr) = 0))
    #define RESIZE(ptr, nbytes)     ((ptr) = Mem_resize((ptr), \
        (nbytes), __FILE__, __LINE__))
    #endif

     

     

    mem.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/mem.doc,v 1.12 1997/10/27 23:08:05 drh Exp $";
    #include <stdlib.h>
    #include <stddef.h>
    #include "assert.h"
    #include "except.h"
    #include "mem.h"
    const Except_T Mem_Failed = { "Allocation Failed" };
    void *Mem_alloc(long nbytes, const char *file, int line){
        void *ptr;
        assert(nbytes > 0);
        ptr = malloc(nbytes);
        if (ptr == NULL)
            {
                if (file == NULL)
                    RAISE(Mem_Failed);
                else
                    Except_raise(&Mem_Failed, file, line);
            }
        return ptr;
    }
    void *Mem_calloc(long count, long nbytes,
        const char *file, int line) {
        void *ptr;
        assert(count > 0);
        assert(nbytes > 0);
        ptr = calloc(count, nbytes);
        if (ptr == NULL)
            {
                if (file == NULL)
                    RAISE(Mem_Failed);
                else
                    Except_raise(&Mem_Failed, file, line);
            }
        return ptr;
    }
    void Mem_free(void *ptr, const char *file, int line) {
        if (ptr)
            free(ptr);
    }
    void *Mem_resize(void *ptr, long nbytes,
        const char *file, int line) {
        assert(ptr);
        assert(nbytes > 0);
        ptr = realloc(ptr, nbytes);
        if (ptr == NULL)
            {
                if (file == NULL)
                    RAISE(Mem_Failed);
                else
                    Except_raise(&Mem_Failed, file, line);
            }
        return ptr;
    }

     

    第6章 进一步内存管理

    arena.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/arena.doc,v 1.10 1997/02/21 19:45:19 drh Exp $ */
    #ifndef ARENA_INCLUDED
    #define ARENA_INCLUDED
    #include "except.h"
    #define T Arena_T
    typedef struct T *T;
    extern const Except_T Arena_NewFailed;
    extern const Except_T Arena_Failed;
    extern T    Arena_new    (void);
    extern void Arena_dispose(T *ap);
    extern void *Arena_alloc (T arena, long nbytes,
        const char *file, int line);
    extern void *Arena_calloc(T arena, long count,
        long nbytes, const char *file, int line);
    extern void  Arena_free  (T arena);
    #undef T
    #endif

     

    arena.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/arena.doc,v 1.10 1997/02/21 19:45:19 drh Exp $";
    #include <stdlib.h>
    #include <string.h>
    #include "assert.h"
    #include "except.h"
    #include "arena.h"
    #define T Arena_T
    const Except_T Arena_NewFailed =
        { "Arena Creation Failed" };
    const Except_T Arena_Failed    =
        { "Arena Allocation Failed" };
    #define THRESHOLD 10
    struct T {
        T prev;
        char *avail;
        char *limit;
    };
    union align {
    #ifdef MAXALIGN
        char pad[MAXALIGN];
    #else
        int i;
        long l;
        long *lp;
        void *p;
        void (*fp)(void);
        float f;
        double d;
        long double ld;
    #endif
    };
    union header {
        struct T b;
        union align a;
    };
    static T freechunks;
    static int nfree;
    T Arena_new(void) {
        T arena = malloc(sizeof (*arena));
        if (arena == NULL)
            RAISE(Arena_NewFailed);
        arena->prev = NULL;
        arena->limit = arena->avail = NULL;
        return arena;
    }
    void Arena_dispose(T *ap) {
        assert(ap && *ap);
        Arena_free(*ap);
        free(*ap);
        *ap = NULL;
    }
    void *Arena_alloc(T arena, long nbytes,
        const char *file, int line) {
        assert(arena);
        assert(nbytes > 0);
        nbytes = ((nbytes + sizeof (union align) - 1)/
            (sizeof (union align)))*(sizeof (union align));
        while (nbytes > arena->limit - arena->avail) {
            T ptr;
            char *limit;
            if ((ptr = freechunks) != NULL) {
                freechunks = freechunks->prev;
                nfree--;
                limit = ptr->limit;
            } else {
                long m = sizeof (union header) + nbytes + 10*1024;
                ptr = malloc(m);
                if (ptr == NULL)
                    {
                        if (file == NULL)
                            RAISE(Arena_Failed);
                        else
                            Except_raise(&Arena_Failed, file, line);
                    }
                limit = (char *)ptr + m;
            }
            *ptr = *arena;
            arena->avail = (char *)((union header *)ptr + 1);
            arena->limit = limit;
            arena->prev  = ptr;
        }
        arena->avail += nbytes;
        return arena->avail - nbytes;
    }
    void *Arena_calloc(T arena, long count, long nbytes,
        const char *file, int line) {
        void *ptr;
        assert(count > 0);
        ptr = Arena_alloc(arena, count*nbytes, file, line);
        memset(ptr, '\0', count*nbytes);
        return ptr;
    }
    void Arena_free(T arena) {
        assert(arena);
        while (arena->prev) {
            struct T tmp = *arena->prev;
            if (nfree < THRESHOLD) {
                arena->prev->prev = freechunks;
                freechunks = arena->prev;
                nfree++;
                freechunks->limit = arena->limit;
            } else
                free(arena->prev);
            *arena = tmp;
        }
        assert(arena->limit == NULL);
        assert(arena->avail == NULL);
    }

     

    第7章 链表

     

    list.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/list.doc,v 1.11 1997/02/21 19:46:01 drh Exp $ */
    #ifndef LIST_INCLUDED
    #define LIST_INCLUDED
    #define T List_T
    typedef struct T *T;
    struct T {
        T rest;
        void *first;
    };
    extern T      List_append (T list, T tail);
    extern T      List_copy   (T list);
    extern T      List_list   (void *x, ...);
    extern T      List_pop    (T list, void **x);
    extern T      List_push   (T list, void *x);
    extern T      List_reverse(T list);
    extern int    List_length (T list);
    extern void   List_free   (T *list);
    extern void   List_map    (T list,
        void apply(void **x, void *cl), void *cl);
    extern void **List_toArray(T list, void *end);
    #undef T
    #endif

     

    list.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/list.doc,v 1.11 1997/02/21 19:46:01 drh Exp $";
    #include <stdarg.h>
    #include <stddef.h>
    #include "assert.h"
    #include "mem.h"
    #include "list.h"
    #define T List_T
    T List_push(T list, void *x) {
        T p;
        NEW(p);
        p->first = x;
        p->rest  = list;
        return p;
    }
    T List_list(void *x, ...) {
        va_list ap;
        T list, *p = &list;
        va_start(ap, x);
        for ( ; x; x = va_arg(ap, void *)) {
            NEW(*p);
            (*p)->first = x;
            p = &(*p)->rest;
        }
        *p = NULL;
        va_end(ap);
        return list;
    }
    T List_append(T list, T tail) {
        T *p = &list;
        while (*p)
            p = &(*p)->rest;
        *p = tail;
        return list;
    }
    T List_copy(T list) {
        T head, *p = &head;
        for ( ; list; list = list->rest) {
            NEW(*p);
            (*p)->first = list->first;
            p = &(*p)->rest;
        }
        *p = NULL;
        return head;
    }
    T List_pop(T list, void **x) {
        if (list) {
            T head = list->rest;
            if (x)
                *x = list->first;
            FREE(list);
            return head;
        } else
            return list;
    }
    T List_reverse(T list) {
        T head = NULL, next;
        for ( ; list; list = next) {
            next = list->rest;
            list->rest = head;
            head = list;
        }
        return head;
    }
    int List_length(T list) {
        int n;
        for (n = 0; list; list = list->rest)
            n++;
        return n;
    }
    void List_free(T *list) {
        T next;
        assert(list);
        for ( ; *list; *list = next) {
            next = (*list)->rest;
            FREE(*list);
        }
    }
    void List_map(T list,
        void apply(void **x, void *cl), void *cl) {
        assert(apply);
        for ( ; list; list = list->rest)
            apply(&list->first, cl);
    }
    void **List_toArray(T list, void *end) {
        int i, n = List_length(list);
        void **array = ALLOC((n + 1)*sizeof (*array));
        for (i = 0; i < n; i++) {
            array[i] = list->first;
            list = list->rest;
        }
        array[i] = end;
        return array;
    }

     

    第8章 表格

    table.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/table.doc,v 1.13 1997/10/27 23:10:11 drh Exp $ */
    #ifndef TABLE_INCLUDED
    #define TABLE_INCLUDED
    #define T Table_T
    typedef struct T *T;
    extern T    Table_new (int hint,
        int cmp(const void *x, const void *y),
        unsigned hash(const void *key));
    extern void Table_free(T *table);
    extern int   Table_length(T table);
    extern void *Table_put   (T table, const void *key,
        void *value);
    extern void *Table_get   (T table, const void *key);
    extern void *Table_remove(T table, const void *key);
    extern void   Table_map    (T table,
        void apply(const void *key, void **value, void *cl),
        void *cl);
    extern void **Table_toArray(T table, void *end);
    #undef T
    #endif

     

     

    table.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/table.doc,v 1.13 1997/10/27 23:10:11 drh Exp $";
    #include <limits.h>
    #include <stddef.h>
    #include "mem.h"
    #include "assert.h"
    #include "table.h"
    #define T Table_T
    struct T {
        int size;
        int (*cmp)(const void *x, const void *y);
        unsigned (*hash)(const void *key);
        int length;
        unsigned timestamp;
        struct binding {
            struct binding *link;
            const void *key;
            void *value;
        } **buckets;
    };
    static int cmpatom(const void *x, const void *y) {
        return x != y;
    }
    static unsigned hashatom(const void *key) {
        return (unsigned long)key>>2;
    }
    T Table_new(int hint,
        int cmp(const void *x, const void *y),
        unsigned hash(const void *key)) {
        T table;
        int i;
        static int primes[] = { 509509102120534093,
            8191163813277165521, INT_MAX };
        assert(hint >= 0);
        for (i = 1; primes[i] < hint; i++)
            ;
        table = ALLOC(sizeof (*table) +
            primes[i-1]*sizeof (table->buckets[0]));
        table->size = primes[i-1];
        table->cmp  = cmp  ?  cmp : cmpatom;
        table->hash = hash ? hash : hashatom;
        table->buckets = (struct binding **)(table + 1);
        for (i = 0; i < table->size; i++)
            table->buckets[i] = NULL;
        table->length = 0;
        table->timestamp = 0;
        return table;
    }
    void *Table_get(T table, const void *key) {
        int i;
        struct binding *p;
        assert(table);
        assert(key);
        i = (*table->hash)(key)%table->size;
        for (p = table->buckets[i]; p; p = p->link)
            if ((*table->cmp)(key, p->key) == 0)
                break;
        return p ? p->value : NULL;
    }
    void *Table_put(T table, const void *key, void *value) {
        int i;
        struct binding *p;
        void *prev;
        assert(table);
        assert(key);
        i = (*table->hash)(key)%table->size;
        for (p = table->buckets[i]; p; p = p->link)
            if ((*table->cmp)(key, p->key) == 0)
                break;
        if (p == NULL) {
            NEW(p);
            p->key = key;
            p->link = table->buckets[i];
            table->buckets[i] = p;
            table->length++;
            prev = NULL;
        } else
            prev = p->value;
        p->value = value;
        table->timestamp++;
        return prev;
    }
    int Table_length(T table) {
        assert(table);
        return table->length;
    }
    void Table_map(T table,
        void apply(const void *key, void **value, void *cl),
        void *cl) {
        int i;
        unsigned stamp;
        struct binding *p;
        assert(table);
        assert(apply);
        stamp = table->timestamp;
        for (i = 0; i < table->size; i++)
            for (p = table->buckets[i]; p; p = p->link) {
                apply(p->key, &p->value, cl);
                assert(table->timestamp == stamp);
            }
    }
    void *Table_remove(T table, const void *key) {
        int i;
        struct binding **pp;
        assert(table);
        assert(key);
        table->timestamp++;
        i = (*table->hash)(key)%table->size;
        for (pp = &table->buckets[i]; *pp; pp = &(*pp)->link)
            if ((*table->cmp)(key, (*pp)->key) == 0) {
                struct binding *p = *pp;
                void *value = p->value;
                *pp = p->link;
                FREE(p);
                table->length--;
                return value;
            }
        return NULL;
    }
    void **Table_toArray(T table, void *end) {
        int i, j = 0;
        void **array;
        struct binding *p;
        assert(table);
        array = ALLOC((2*table->length + 1)*sizeof (*array));
        for (i = 0; i < table->size; i++)
            for (p = table->buckets[i]; p; p = p->link) {
                array[j++] = (void *)p->key;
                array[j++] = p->value;
            }
        array[j] = end;
        return array;
    }
    void Table_free(T *table) {
        assert(table && *table);
        if ((*table)->length > 0) {
            int i;
            struct binding *p, *q;
            for (i = 0; i < (*table)->size; i++)
                for (p = (*table)->buckets[i]; p; p = q) {
                    q = p->link;
                    FREE(p);
                }
        }
        FREE(*table);
    }

     

     

    wf程序来统计单词的频率

    getword.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/table.doc,v 1.13 1997/10/27 23:10:11 drh Exp $";
    #include <ctype.h>
    #include <string.h>
    #include <stdio.h>
    #include "assert.h"
    #include "getword.h"
    int getword(FILE *fp, char *buf, int size,
        int first(int c), int rest(int c)) {
        int i = 0, c;
        assert(fp && buf && size > 1 && first && rest);
        c = getc(fp);
        for ( ; c != EOF; c = getc(fp))
            if (first(c)) {
                {
                    if (i < size - 1)
                        buf[i++] = c;
                }
                c = getc(fp);
                break;
            }
        for ( ; c != EOF && rest(c); c = getc(fp))
            {
                if (i < size - 1)
                    buf[i++] = c;
            }
        if (i < size)
            buf[i] = '\0';
        else
            buf[size-1] = '\0';
        if (c != EOF)
            ungetc(c, fp);
        return i > 0;
    }

     

    wf.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/table.doc,v 1.13 1997/10/27 23:10:11 drh Exp $";
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <ctype.h>
    #include "atom.h"
    #include "table.h"
    #include "mem.h"
    #include "getword.h"
    #include <string.h>
    void wf(char *, FILE *);
    int first(int c);
    int rest (int c);
    int compare(const void *x, const void *y);
    void vfree(const void *, void **, void *);
    int main(int argc, char *argv[]) {
        int i;
        for (i = 1; i < argc; i++) {
            FILE *fp = fopen(argv[i], "r");
            if (fp == NULL) {
                fprintf(stderr, "%s: can't open '%s' (%s)\n",
                    argv[0], argv[i], strerror(errno));
                return EXIT_FAILURE;
            } else {
                wf(argv[i], fp);
                fclose(fp);
            }
        }
        if (argc == 1) wf(NULL, stdin);
        return EXIT_SUCCESS;
    }
    void wf(char *name, FILE *fp) {
        Table_T table = Table_new(0, NULL, NULL);
        char buf[128];
        while (getword(fp, buf, sizeof buf, first, rest)) {
            const char *word;
            int i, *count;
            for (i = 0; buf[i] != '\0'; i++)
                buf[i] = tolower(buf[i]);
            word = Atom_string(buf);
            count = Table_get(table, word);
            if (count)
                (*count)++;
            else {
                NEW(count);
                *count = 1;
                Table_put(table, word, count);
            }
        }
        if (name)
            printf("%s:\n", name);
        { int i;
          void **array = Table_toArray(table, NULL);
          qsort(array, Table_length(table), 2*sizeof (*array),
              compare);
          for (i = 0; array[i]; i += 2)
              printf("%d\t%s\n", *(int *)array[i+1],
                  (char *)array[i]);
          FREE(array); }
        Table_map(table, vfree, NULL);
        Table_free(&table);
    }
    int first(int c) {
        return isalpha(c);
    }
    int rest(int c) {
        return isalpha(c) || c == '_';
    }
    int compare(const void *x, const void *y) {
        return strcmp(*(char **)x, *(char **)y);
    }
    void vfree(const void *key, void **count, void *cl) {
        FREE(*count);
    }

     

    第9章 集合

    集合的实现

    set.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/set.doc,v 1.11 1996/06/26 23:02:01 drh Exp $ */
    #ifndef SET_INCLUDED
    #define SET_INCLUDED
    #define T Set_T
    typedef struct T *T;
    extern T    Set_new (int hint,
        int cmp(const void *x, const void *y),
        unsigned hash(const void *x));
    extern void Set_free(T *set);
    extern int   Set_length(T set);
    extern int   Set_member(T setconst void *member);
    extern void  Set_put   (T setconst void *member);
    extern void *Set_remove(T setconst void *member);
    extern void   Set_map    (T set,
        void apply(const void *member, void *cl), void *cl);
    extern void **Set_toArray(T setvoid *end);
    extern T Set_union(T s, T t);
    extern T Set_inter(T s, T t);
    extern T Set_minus(T s, T t);
    extern T Set_diff (T s, T t);
    #undef T
    #endif

     

     

    set.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/set.doc,v 1.11 1996/06/26 23:02:01 drh Exp $";
    #include <limits.h>
    #include <stddef.h>
    #include "mem.h"
    #include "assert.h"
    #include "arith.h"
    #include "set.h"
    #define T Set_T
    struct T {
        int length;
        unsigned timestamp;
        int (*cmp)(const void *x, const void *y);
        unsigned (*hash)(const void *x);
        int size;
        struct member {
            struct member *link;
            const void *member;
        } **buckets;
    };
    static int cmpatom(const void *x, const void *y) {
        return x != y;
    }
    static unsigned hashatom(const void *x) {
        return (unsigned long)x>>2;
    }
    static T copy(T t, int hint) {
        T set;
        assert(t);
        set = Set_new(hint, t->cmp, t->hash);
        { int i;
          struct member *q;
          for (i = 0; i < t->size; i++)
              for (q = t->buckets[i]; q; q = q->link)
            {
                struct member *p;
                const void *member = q->member;
                int i = (*set->hash)(member)%set->size;
                NEW(p);
                p->member = member;
                p->link = set->buckets[i];
                set->buckets[i] = p;
                set->length++;
            }
        }
        return set;
    }
    T Set_new(int hint,
        int cmp(const void *x, const void *y),
        unsigned hash(const void *x)) {
        T set;
        int i;
        static int primes[] = { 509509102120534093,
            8191163813277165521, INT_MAX };
        assert(hint >= 0);
        for (i = 1; primes[i] < hint; i++)
            ;
        set = ALLOC(sizeof (*set) +
            primes[i-1]*sizeof (set->buckets[0]));
        set->size = primes[i-1];
        set->cmp  = cmp  ?  cmp : cmpatom;
        set->hash = hash ? hash : hashatom;
        set->buckets = (struct member **)(set + 1);
        for (i = 0; i < set->size; i++)
            set->buckets[i] = NULL;
        set->length = 0;
        set->timestamp = 0;
        return set;
    }
    int Set_member(T setconst void *member) {
        int i;
        struct member *p;
        assert(set);
        assert(member);
        i = (*set->hash)(member)%set->size;
        for (p = set->buckets[i]; p; p = p->link)
            if ((*set->cmp)(member, p->member) == 0)
                break;
        return p != NULL;
    }
    void Set_put(T setconst void *member) {
        int i;
        struct member *p;
        assert(set);
        assert(member);
        i = (*set->hash)(member)%set->size;
        for (p = set->buckets[i]; p; p = p->link)
            if ((*set->cmp)(member, p->member) == 0)
                break;
        if (p == NULL) {
            NEW(p);
            p->member = member;
            p->link = set->buckets[i];
            set->buckets[i] = p;
            set->length++;
        } else
            p->member = member;
        set->timestamp++;
    }
    void *Set_remove(T setconst void *member) {
        int i;
        struct member **pp;
        assert(set);
        assert(member);
        set->timestamp++;
        i = (*set->hash)(member)%set->size;
        for (pp = &set->buckets[i]; *pp; pp = &(*pp)->link)
            if ((*set->cmp)(member, (*pp)->member) == 0) {
                struct member *p = *pp;
                *pp = p->link;
                member = p->member;
                FREE(p);
                set->length--;
                return (void *)member;
            }
        return NULL;
    }
    int Set_length(T set) {
        assert(set);
        return set->length;
    }
    void Set_free(T *set) {
        assert(set && *set);
        if ((*set)->length > 0) {
            int i;
            struct member *p, *q;
            for (i = 0; i < (*set)->size; i++)
                for (p = (*set)->buckets[i]; p; p = q) {
                    q = p->link;
                    FREE(p);
                }
        }
        FREE(*set);
    }
    void Set_map(T set,
        void apply(const void *member, void *cl), void *cl) {
        int i;
        unsigned stamp;
        struct member *p;
        assert(set);
        assert(apply);
        stamp = set->timestamp;
        for (i = 0; i < set->size; i++)
            for (p = set->buckets[i]; p; p = p->link) {
                apply(p->member, cl);
                assert(set->timestamp == stamp);
            }
    }
    void **Set_toArray(T setvoid *end) {
        int i, j = 0;
        void **array;
        struct member *p;
        assert(set);
        array = ALLOC((set->length + 1)*sizeof (*array));
        for (i = 0; i < set->size; i++)
            for (p = set->buckets[i]; p; p = p->link)
                array[j++] = (void *)p->member;
        array[j] = end;
        return array;
    }
    T Set_union(T s, T t) {
        if (s == NULL) {
            assert(t);
            return copy(t, t->size);
        } else if (t == NULL)
            return copy(s, s->size);
        else {
            T set = copy(s, Arith_max(s->size, t->size));
            assert(s->cmp == t->cmp && s->hash == t->hash);
            { int i;
              struct member *q;
              for (i = 0; i < t->size; i++)
                  for (q = t->buckets[i]; q; q = q->link)
                Set_put(set, q->member);
            }
            return set;
        }
    }
    T Set_inter(T s, T t) {
        if (s == NULL) {
            assert(t);
            return Set_new(t->size, t->cmp, t->hash);
        } else if (t == NULL)
            return Set_new(s->size, s->cmp, s->hash);
        else if (s->length < t->length)
            return Set_inter(t, s);
        else {
            T set = Set_new(Arith_min(s->size, t->size),
                s->cmp, s->hash);
            assert(s->cmp == t->cmp && s->hash == t->hash);
            { int i;
              struct member *q;
              for (i = 0; i < t->size; i++)
                  for (q = t->buckets[i]; q; q = q->link)
                if (Set_member(s, q->member))
                    {
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
            }
            return set;
        }
    }
    T Set_minus(T t, T s) {
        if (t == NULL){
            assert(s);
            return Set_new(s->size, s->cmp, s->hash);
        } else if (s == NULL)
            return copy(t, t->size);
        else {
            T set = Set_new(Arith_min(s->size, t->size),
                s->cmp, s->hash);
            assert(s->cmp == t->cmp && s->hash == t->hash);
            { int i;
              struct member *q;
              for (i = 0; i < t->size; i++)
                  for (q = t->buckets[i]; q; q = q->link)
                if (!Set_member(s, q->member))
                    {
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
            }
            return set;
        }
    }
    T Set_diff(T s, T t) {
        if (s == NULL) {
            assert(t);
            return copy(t, t->size);
        } else if (t == NULL)
            return copy(s, s->size);
        else {
            T set = Set_new(Arith_min(s->size, t->size),
                s->cmp, s->hash);
            assert(s->cmp == t->cmp && s->hash == t->hash);
            { int i;
              struct member *q;
              for (i = 0; i < t->size; i++)
                  for (q = t->buckets[i]; q; q = q->link)
                if (!Set_member(s, q->member))
                    {
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
            }
            { T u = t; t = s; s = u; }
            { int i;
              struct member *q;
              for (i = 0; i < t->size; i++)
                  for (q = t->buckets[i]; q; q = q->link)
                if (!Set_member(s, q->member))
                    {
                        struct member *p;
                        const void *member = q->member;
                        int i = (*set->hash)(member)%set->size;
                        NEW(p);
                        p->member = member;
                        p->link = set->buckets[i];
                        set->buckets[i] = p;
                        set->length++;
                    }
            }
            return set;
        }
    }

     

    实例:交叉引用列表

    xref.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/set.doc,v 1.11 1996/06/26 23:02:01 drh Exp $";
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include "table.h"
    #include <string.h>
    #include "atom.h"
    #include "set.h"
    #include "mem.h"
    #include "getword.h"
    #include <ctype.h>
    int compare(const void *x, const void *y);
    void print(Table_T);
    int cmpint(const void *x, const void *y);
    void xref(const char *, FILE *, Table_T);
    int first(int c);
    int rest (int c);
    int      intcmp (const void *x, const void *y);
    unsigned inthash(const void *x);
    int linenum;
    int main(int argc, char *argv[]) {
        int i;
        Table_T identifiers = Table_new(0, NULL, NULL);
        for (i = 1; i < argc; i++) {
            FILE *fp = fopen(argv[i], "r");
            if (fp == NULL) {
                fprintf(stderr, "%s: can't open '%s' (%s)\n",
                    argv[0], argv[i], strerror(errno));
                return EXIT_FAILURE;
            } else {
                xref(argv[i], fp, identifiers);
                fclose(fp);
            }
        }
        if (argc == 1) xref(NULL, stdin, identifiers);
        {
            int i;
            void **array = Table_toArray(identifiers, NULL);
            qsort(array, Table_length(identifiers),
                2*sizeof (*array), compare);
            for (i = 0; array[i]; i += 2) {
                printf("%s", (char *)array[i]);
                print(array[i+1]);
            }
            FREE(array);
        }
        return EXIT_SUCCESS;
    }
    int compare(const void *x, const void *y) {
        return strcmp(*(char **)x, *(char **)y);
    }
    void print(Table_T files) {
        int i;
        void **array = Table_toArray(files, NULL);
        qsort(array, Table_length(files), 2*sizeof (*array),
            compare);
        for (i = 0; array[i]; i += 2) {
            if (*(char *)array[i] != '\0')
                printf("\t%s:", (char *)array[i]);
            {
                int j;
                void **lines = Set_toArray(array[i+1], NULL);
                qsort(lines, Set_length(array[i+1]), sizeof (*lines),
                    cmpint);
                for (j = 0; lines[j]; j++)
                    printf(" %d", *(int *)lines[j]);
                FREE(lines);
            }
            printf("\n");
        }
        FREE(array);
    }
    int cmpint(const void *x, const void *y) {
        if (**(int **)x < **(int **)y)
            return -1;
        else if (**(int **)x > **(int **)y)
            return +1;
        else
            return 0;
    }
    void xref(const char *name, FILE *fp,
            Table_T identifiers){
        char buf[128];
        if (name == NULL)
            name = "";
        name = Atom_string(name);
        linenum = 1;
        while (getword(fp, buf, sizeof buf, first, rest)) {
            Set_T set;
            Table_T files;
            const char *id = Atom_string(buf);
            files = Table_get(identifiers, id);
            if (files == NULL) {
                files = Table_new(0, NULL, NULL);
                Table_put(identifiers, id, files);
            }
            set = Table_get(files, name);
            if (set == NULL) {
                set = Set_new(0, intcmp, inthash);
                Table_put(files, name, set);
            }
            {
                int *p = &linenum;
                if (!Set_member(set, p)) {
                    NEW(p);
                    *p = linenum;
                    Set_put(set, p);
                }
            }
        }
    }
    int first(int c) {
        if (c == '\n')
            linenum++;
        return isalpha(c) || c == '_';
    }
    int rest(int c) {
        return isalpha(c) || c == '_' || isdigit(c);
    }
    int intcmp(const void *x, const void *y) {
        return cmpint(&x, &y);
    }
    unsigned inthash(const void *x) {
        return *(int *)x;
    }

     

     

    第10章 动态数组

    array.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/array.doc,v 1.11 1997/10/29 22:05:21 drh Exp $ */
    #ifndef ARRAY_INCLUDED
    #define ARRAY_INCLUDED
    #define T Array_T
    typedef struct T *T;
    extern T    Array_new (int length, int size);
    extern void Array_free(T *array);
    extern int Array_length(T array);
    extern int Array_size  (T array);
    extern void *Array_get(T array, int i);
    extern void *Array_put(T array, int i, void *elem);
    extern void Array_resize(T array, int length);
    extern T    Array_copy  (T array, int length);
    #undef T
    #endif

     

    array.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/array.doc,v 1.11 1997/10/29 22:05:21 drh Exp $";
    #include <stdlib.h>
    #include <string.h>
    #include "assert.h"
    #include "array.h"
    #include "arrayrep.h"
    #include "mem.h"
    #define T Array_T
    T Array_new(int length, int size) {
        T array;
        NEW(array);
        if (length > 0)
            ArrayRep_init(array, length, size,
                CALLOC(length, size));
        else
            ArrayRep_init(array, length, size, NULL);
        return array;
    }
    void ArrayRep_init(T array, int length, int size,
        void *ary) {
        assert(array);
        assert(ary && length>0 || length==0 && ary==NULL);
        assert(size > 0);
        array->length = length;
        array->size   = size;
        if (length > 0)
            array->array = ary;
        else
            array->array = NULL;
    }
    void Array_free(T *array) {
        assert(array && *array);
        FREE((*array)->array);
        FREE(*array);
    }
    void *Array_get(T array, int i) {
        assert(array);
        assert(i >= 0 && i < array->length);
        return array->array + i*array->size;
    }
    void *Array_put(T array, int i, void *elem) {
        assert(array);
        assert(i >= 0 && i < array->length);
        assert(elem);
        memcpy(array->array + i*array->size, elem,
            array->size);
        return elem;
    }
    int Array_length(T array) {
        assert(array);
        return array->length;
    }
    int Array_size(T array) {
        assert(array);
        return array->size;
    }
    void Array_resize(T array, int length) {
        assert(array);
        assert(length >= 0);
        if (length == 0)
            FREE(array->array);
        else if (array->length == 0)
            array->array = ALLOC(length*array->size);
        else
            RESIZE(array->array, length*array->size);
        array->length = length;
    }
    T Array_copy(T array, int length) {
        T copy;
        assert(array);
        assert(length >= 0);
        copy = Array_new(length, array->size);
        if (copy->length >= array->length
        && array->length > 0)
            memcpy(copy->array, array->array, array->length);
        else if (array->length > copy->length
        && copy->length > 0)
            memcpy(copy->array, array->array, copy->length);
        return copy;
    }

     

    第11章 序列

    seq.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/seq.doc,v 1.11 1997/02/21 19:48:24 drh Exp $ */
    #ifndef SEQ_INCLUDED
    #define SEQ_INCLUDED
    #define T Seq_T
    typedef struct T *T;
    extern T Seq_new(int hint);
    extern T Seq_seq(void *x, ...);
    extern void Seq_free(T *seq);
    extern int Seq_length(T seq);
    extern void *Seq_get(T seq, int i);
    extern void *Seq_put(T seq, int i, void *x);
    extern void *Seq_addlo(T seq, void *x);
    extern void *Seq_addhi(T seq, void *x);
    extern void *Seq_remlo(T seq);
    extern void *Seq_remhi(T seq);
    #undef T
    #endif

     

    seq.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/seq.doc,v 1.11 1997/02/21 19:48:24 drh Exp $";
    #include <stdlib.h>
    #include <stdarg.h>
    #include <string.h>
    #include "assert.h"
    #include "seq.h"
    #include "array.h"
    #include "arrayrep.h"
    #include "mem.h"
    #define T Seq_T
    struct T {
        struct Array_T array;
        int length;
        int head;
    };
    static void expand(T seq) {
        int n = seq->array.length;
        Array_resize(&seq->array, 2*n);
        if (seq->head > 0)
            {
                void **old = &((void **)seq->array.array)[seq->head];
                memcpy(old+n, old, (n - seq->head)*sizeof (void *));
                seq->head += n;
            }
    }
    T Seq_new(int hint) {
        T seq;
        assert(hint >= 0);
        NEW0(seq);
        if (hint == 0)
            hint = 16;
        ArrayRep_init(&seq->array, hint, sizeof (void *),
            ALLOC(hint*sizeof (void *)));
        return seq;
    }
    T Seq_seq(void *x, ...) {
        va_list ap;
        T seq = Seq_new(0);
        va_start(ap, x);
        for ( ; x; x = va_arg(ap, void *))
            Seq_addhi(seq, x);
        va_end(ap);
        return seq;
    }
    void Seq_free(T *seq) {
        assert(seq && *seq);
        assert((void *)*seq == (void *)&(*seq)->array);
        Array_free((Array_T *)seq);
    }
    int Seq_length(T seq) {
        assert(seq);
        return seq->length;
    }
    void *Seq_get(T seq, int i) {
        assert(seq);
        assert(i >= 0 && i < seq->length);
        return ((void **)seq->array.array)[
                   (seq->head + i)%seq->array.length];
    }
    void *Seq_put(T seq, int i, void *x) {
        void *prev;
        assert(seq);
        assert(i >= 0 && i < seq->length);
        prev = ((void **)seq->array.array)[
                   (seq->head + i)%seq->array.length];
        ((void **)seq->array.array)[
            (seq->head + i)%seq->array.length] = x;
        return prev;
    }
    void *Seq_remhi(T seq) {
        int i;
        assert(seq);
        assert(seq->length > 0);
        i = --seq->length;
        return ((void **)seq->array.array)[
                   (seq->head + i)%seq->array.length];
    }
    void *Seq_remlo(T seq) {
        int i = 0;
        void *x;
        assert(seq);
        assert(seq->length > 0);
        x = ((void **)seq->array.array)[
                (seq->head + i)%seq->array.length];
        seq->head = (seq->head + 1)%seq->array.length;
        --seq->length;
        return x;
    }
    void *Seq_addhi(T seq, void *x) {
        int i;
        assert(seq);
        if (seq->length == seq->array.length)
            expand(seq);
        i = seq->length++;
        return ((void **)seq->array.array)[
                   (seq->head + i)%seq->array.length] = x;
    }
    void *Seq_addlo(T seq, void *x) {
        int i = 0;
        assert(seq);
        if (seq->length == seq->array.length)
            expand(seq);
        if (--seq->head < 0)
            seq->head = seq->array.length - 1;
        seq->length++;
        return ((void **)seq->array.array)[
                   (seq->head + i)%seq->array.length] = x;
    }

     

    第12章 环

    ring.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/ring.doc,v 1.12 1997/02/21 19:49:24 drh Exp $ */
    #ifndef RING_INCLUDED
    #define RING_INCLUDED
    #define T Ring_T
    typedef struct T *T;
    extern T Ring_new (void);
    extern T Ring_ring(void *x, ...);
    extern void Ring_free  (T *ring);
    extern int  Ring_length(T  ring);
    extern void *Ring_get(T ring, int i);
    extern void *Ring_put(T ring, int i, void *x);
    extern void *Ring_add(T ring, int pos, void *x);
    extern void *Ring_addlo(T ring, void *x);
    extern void *Ring_addhi(T ring, void *x);
    extern void *Ring_remove(T ring, int i);
    extern void *Ring_remlo(T ring);
    extern void *Ring_remhi(T ring);
    extern void Ring_rotate(T ring, int n);
    #undef T
    #endif

     

    ring.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/ring.doc,v 1.12 1997/02/21 19:49:24 drh Exp $";
    #include <stdlib.h>
    #include <stdarg.h>
    #include <string.h>
    #include "assert.h"
    #include "ring.h"
    #include "mem.h"
    #define T Ring_T
    struct T {
        struct node {
            struct node *llink, *rlink;
            void *value;
        } *head;
        int length;
    };
    T Ring_new(void) {
        T ring;
        NEW0(ring);
        ring->head = NULL;
        return ring;
    }
    T Ring_ring(void *x, ...) {
        va_list ap;
        T ring = Ring_new();
        va_start(ap, x);
        for ( ; x; x = va_arg(ap, void *))
            Ring_addhi(ring, x);
        va_end(ap);
        return ring;
    }
    void Ring_free(T *ring) {
        struct node *p, *q;
        assert(ring && *ring);
        if ((p = (*ring)->head) != NULL) {
            int n = (*ring)->length;
            for ( ; n-- > 0; p = q) {
                q = p->rlink;
                FREE(p);
            }
        }
        FREE(*ring);
    }
    int Ring_length(T ring) {
        assert(ring);
        return ring->length;
    }
    void *Ring_get(T ring, int i) {
        struct node *q;
        assert(ring);
        assert(i >= 0 && i < ring->length);
        {
            int n;
            q = ring->head;
            if (i <= ring->length/2)
                for (n = i; n-- > 0; )
                    q = q->rlink;
            else
                for (n = ring->length - i; n-- > 0; )
                    q = q->llink;
        }
        return q->value;
    }
    void *Ring_put(T ring, int i, void *x) {
        struct node *q;
        void *prev;
        assert(ring);
        assert(i >= 0 && i < ring->length);
        {
            int n;
            q = ring->head;
            if (i <= ring->length/2)
                for (n = i; n-- > 0; )
                    q = q->rlink;
            else
                for (n = ring->length - i; n-- > 0; )
                    q = q->llink;
        }
        prev = q->value;
        q->value = x;
        return prev;
    }
    void *Ring_addhi(T ring, void *x) {
        struct node *p, *q;
        assert(ring);
        NEW(p);
        if ((q = ring->head) != NULL)
            {
                p->llink = q->llink;
                q->llink->rlink = p;
                p->rlink = q;
                q->llink = p;
            }
        else
            ring->head = p->llink = p->rlink = p;
        ring->length++;
        return p->value = x;
    }
    void *Ring_addlo(T ring, void *x) {
        assert(ring);
        Ring_addhi(ring, x);
        ring->head = ring->head->llink;
        return x;
    }
    void *Ring_add(T ring, int pos, void *x) {
        assert(ring);
        assert(pos >= -ring->length && pos<=ring->length+1);
        if (pos == 1 || pos == -ring->length)
            return Ring_addlo(ring, x);
        else if (pos == 0 || pos == ring->length + 1)
            return Ring_addhi(ring, x);
        else {
            struct node *p, *q;
            int i = pos < 0 ? pos + ring->length : pos - 1;
            {
                int n;
                q = ring->head;
                if (i <= ring->length/2)
                    for (n = i; n-- > 0; )
                        q = q->rlink;
                else
                    for (n = ring->length - i; n-- > 0; )
                        q = q->llink;
            }
            NEW(p);
            {
                p->llink = q->llink;
                q->llink->rlink = p;
                p->rlink = q;
                q->llink = p;
            }
            ring->length++;
            return p->value = x;
        }
    }
    void *Ring_remove(T ring, int i) {
        void *x;
        struct node *q;
        assert(ring);
        assert(ring->length > 0);
        assert(i >= 0 && i < ring->length);
        {
            int n;
            q = ring->head;
            if (i <= ring->length/2)
                for (n = i; n-- > 0; )
                    q = q->rlink;
            else
                for (n = ring->length - i; n-- > 0; )
                    q = q->llink;
        }
        if (i == 0)
            ring->head = ring->head->rlink;
        x = q->value;
        q->llink->rlink = q->rlink;
        q->rlink->llink = q->llink;
        FREE(q);
        if (--ring->length == 0)
            ring->head = NULL;
        return x;
    }
    void *Ring_remhi(T ring) {
        void *x;
        struct node *q;
        assert(ring);
        assert(ring->length > 0);
        q = ring->head->llink;
        x = q->value;
        q->llink->rlink = q->rlink;
        q->rlink->llink = q->llink;
        FREE(q);
        if (--ring->length == 0)
            ring->head = NULL;
        return x;
    }
    void *Ring_remlo(T ring) {
        assert(ring);
        assert(ring->length > 0);
        ring->head = ring->head->rlink;
        return Ring_remhi(ring);
    }
    void Ring_rotate(T ring, int n) {
        struct node *q;
        int i;
        assert(ring);
        assert(n >= -ring->length && n <= ring->length);
        if (n >= 0)
            i = n%ring->length;
        else
            i = n + ring->length;
        {
            int n;
            q = ring->head;
            if (i <= ring->length/2)
                for (n = i; n-- > 0; )
                    q = q->rlink;
            else
                for (n = ring->length - i; n-- > 0; )
                    q = q->llink;
        }
        ring->head = q;
    }

     

    第13章 位向量

    bit.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/bit.doc,v 1.15 1997/02/21 19:49:56 drh Exp $ */
    #ifndef BIT_INCLUDED
    #define BIT_INCLUDED
    #define T Bit_T
    typedef struct T *T;
    extern T   Bit_new   (int length);
    extern int Bit_length(T set);
    extern int Bit_count (T set);
    extern void Bit_free(T *set);
    extern int Bit_get(T setint n);
    extern int Bit_put(T setint n, int bit);
    extern void Bit_clear(T setint lo, int hi);
    extern void Bit_set  (T setint lo, int hi);
    extern void Bit_not  (T setint lo, int hi);
    extern int Bit_lt (T s, T t);
    extern int Bit_eq (T s, T t);
    extern int Bit_leq(T s, T t);
    extern void Bit_map(T set,
         void apply(int n, int bit, void *cl), void *cl);
    extern T Bit_union(T s, T t);
    extern T Bit_inter(T s, T t);
    extern T Bit_minus(T s, T t);
    extern T Bit_diff (T s, T t);
    #undef T
    #endif

     

    bit.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/bit.doc,v 1.15 1997/02/21 19:49:56 drh Exp $";
    #include <stdarg.h>
    #include <string.h>
    #include "assert.h"
    #include "bit.h"
    #include "mem.h"
    #define T Bit_T
    struct T {
        int length;
        unsigned char *bytes;
        unsigned long *words;
    };
    #define BPW (8*sizeof (unsigned long))
    #define nwords(len) ((((len) + BPW - 1)&(~(BPW-1)))/BPW)
    #define nbytes(len) ((((len) + 8 - 1)&(~(8-1)))/8)
    #define setop(sequal, snull, tnull, op) \
        if (s == t) { assert(s); return sequal; } \
        else if (s == NULL) { assert(t); return snull; } \
        else if (t == NULL) return tnull; \
        else { \
            int i; T set; \
            assert(s->length == t->length); \
            set = Bit_new(s->length); \
            for (i = nwords(s->length); --i >= 0; ) \
                set->words[i] = s->words[i] op t->words[i]; \
            return set; }
    unsigned char msbmask[] = {
        0xFF0xFE0xFC0xF8,
        0xF00xE00xC00x80
    };
    unsigned char lsbmask[] = {
        0x010x030x070x0F,
        0x1F0x3F0x7F0xFF
    };
    static T copy(T t) {
        T set;
        assert(t);
        set = Bit_new(t->length);
        if (t->length > 0)
            memcpy(set->bytes, t->bytes, nbytes(t->length));
        return set;
    }
    T Bit_new(int length) {
        T set;
        assert(length >= 0);
        NEW(set);
        if (length > 0)
            set->words = CALLOC(nwords(length),
                sizeof (unsigned long));
        else
            set->words = NULL;
        set->bytes = (unsigned char *)set->words;
        set->length = length;
        return set;
    }
    void Bit_free(T *set) {
        assert(set && *set);
        FREE((*set)->words);
        FREE(*set);
    }
    int Bit_length(T set) {
        assert(set);
        return set->length;
    }
    int Bit_count(T set) {
        int length = 0, n;
        static char count[] = {
            0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
        assert(set);
        for (n = nbytes(set->length); --n >= 0; ) {
            unsigned char c = set->bytes[n];
            length += count[c&0xF] + count[c>>4];
        }
        return length;
    }
    int Bit_get(T setint n) {
        assert(set);
        assert(0 <= n && n < set->length);
        return ((set->bytes[n/8]>>(n%8))&1);
    }
    int Bit_put(T setint n, int bit) {
        int prev;
        assert(set);
        assert(bit == 0 || bit == 1);
        assert(0 <= n && n < set->length);
        prev = ((set->bytes[n/8]>>(n%8))&1);
        if (bit == 1)
            set->bytes[n/8] |=   1<<(n%8);
        else
            set->bytes[n/8] &= ~(1<<(n%8));
        return prev;
    }
    void Bit_set(T setint lo, int hi) {
            assert(set);
            assert(0 <= lo && hi < set->length);
            assert(lo <= hi);
        if (lo/8 < hi/8) {
            set->bytes[lo/8] |= msbmask[lo%8];
            {
                int i;
                for (i = lo/8+1; i < hi/8; i++)
                    set->bytes[i] = 0xFF;
            }
            set->bytes[hi/8] |= lsbmask[hi%8];
        } else
            set->bytes[lo/8] |= (msbmask[lo%8]&lsbmask[hi%8]);
    }
    void Bit_clear(T setint lo, int hi) {
            assert(set);
            assert(0 <= lo && hi < set->length);
            assert(lo <= hi);
        if (lo/8 < hi/8) {
            int i;
            set->bytes[lo/8] &= ~msbmask[lo%8];
            for (i = lo/8+1; i < hi/8; i++)
                set->bytes[i] = 0;
            set->bytes[hi/8] &= ~lsbmask[hi%8];
        } else
            set->bytes[lo/8] &= ~(msbmask[lo%8]&lsbmask[hi%8]);
    }
    void Bit_not(T setint lo, int hi) {
            assert(set);
            assert(0 <= lo && hi < set->length);
            assert(lo <= hi);
        if (lo/8 < hi/8) {
            int i;
            set->bytes[lo/8] ^= msbmask[lo%8];
            for (i = lo/8+1; i < hi/8; i++)
                set->bytes[i] ^= 0xFF;
            set->bytes[hi/8] ^= lsbmask[hi%8];
        } else
            set->bytes[lo/8] ^= (msbmask[lo%8]&lsbmask[hi%8]);
    }
    void Bit_map(T set,
        void apply(int n, int bit, void *cl), void *cl) {
        int n;
        assert(set);
        for (n = 0; n < set->length; n++)
            apply(n, ((set->bytes[n/8]>>(n%8))&1), cl);
    }
    int Bit_eq(T s, T t) {
        int i;
        assert(s && t);
        assert(s->length == t->length);
        for (i = nwords(s->length); --i >= 0; )
            if (s->words[i] != t->words[i])
                return 0;
        return 1;
    }
    int Bit_leq(T s, T t) {
        int i;
        assert(s && t);
        assert(s->length == t->length);
        for (i = nwords(s->length); --i >= 0; )
            if ((s->words[i]&~t->words[i]) != 0)
                return 0;
        return 1;
    }
    int Bit_lt(T s, T t) {
        int i, lt = 0;
        assert(s && t);
        assert(s->length == t->length);
        for (i = nwords(s->length); --i >= 0; )
            if ((s->words[i]&~t->words[i]) != 0)
                return 0;
            else if (s->words[i] != t->words[i])
                lt |= 1;
        return lt;
    }
    T Bit_union(T s, T t) {
        setop(copy(t), copy(t), copy(s), |)
    }
    T Bit_inter(T s, T t) {
        setop(copy(t),
            Bit_new(t->length), Bit_new(s->length), &)
    }
    T Bit_minus(T s, T t) {
        setop(Bit_new(s->length),
            Bit_new(t->length), copy(s), & ~)
    }
    T Bit_diff(T s, T t) {
        setop(Bit_new(s->length), copy(t), copy(s), ^)
    }

     

    fmt.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/fmt.doc,v 1.10 1996/06/26 23:02:01 drh Exp $ */
    #ifndef FMT_INCLUDED
    #define FMT_INCLUDED
    #include <stdarg.h>
    #include <stdio.h>
    #include "except.h"
    #define T Fmt_T
    typedef void (*T)(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[256], int width, int precision);
    extern char *Fmt_flags;
    extern const Except_T Fmt_Overflow;
    extern void Fmt_fmt (int put(int c, void *cl), void *cl,
        const char *fmt, ...);
    extern void Fmt_vfmt(int put(int c, void *cl), void *cl,
        const char *fmt, va_list ap);
    extern void Fmt_print (const char *fmt, ...);
    extern void Fmt_fprint(FILE *stream,
        const char *fmt, ...);
    extern int Fmt_sfmt   (char *buf, int size,
        const char *fmt, ...);
    extern int Fmt_vsfmt(char *buf, int size,
        const char *fmt, va_list ap);
    extern char *Fmt_string (const char *fmt, ...);
    extern char *Fmt_vstring(const char *fmt, va_list ap);
    extern T Fmt_register(int code, T cvt);
    extern void Fmt_putd(const char *str, int len,
        int put(int c, void *cl), void *cl,
        unsigned char flags[256], int width, int precision);
    extern void Fmt_puts(const char *str, int len,
        int put(int c, void *cl), void *cl,
        unsigned char flags[256], int width, int precision);
    #undef T
    #endif

     

    fmt.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/fmt.doc,v 1.10 1996/06/26 23:02:01 drh Exp $";
    #include <stdarg.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <limits.h>
    #include <float.h>
    #include <ctype.h>
    #include <math.h>
    #include "assert.h"
    #include "except.h"
    #include "fmt.h"
    #include "mem.h"
    #define T Fmt_T
    struct buf {
        char *buf;
        char *bp;
        int size;
    };
    #define pad(n,c) do { int nn = (n); \
        while (nn-- > 0) \
            put((c), cl); } while (0)
    static void cvt_s(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        char *str = va_arg(*app, char *);
        assert(str);
        Fmt_puts(str, strlen(str), put, cl, flags,
            width, precision);
    }
    static void cvt_d(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        int val = va_arg(*app, int);
        unsigned m;
        char buf[43];
        char *p = buf + sizeof buf;
        if (val == INT_MIN)
            m = INT_MAX + 1U;
        else if (val < 0)
            m = -val;
        else
            m = val;
        do
            *--p = m%10 + '0';
        while ((m /= 10) > 0);
        if (val < 0)
            *--p = '-';
        Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
            width, precision);
    }
    static void cvt_u(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        unsigned m = va_arg(*app, unsigned);
        char buf[43];
        char *p = buf + sizeof buf;
        do
            *--p = m%10 + '0';
        while ((m /= 10) > 0);
        Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
            width, precision);
    }
    static void cvt_o(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        unsigned m = va_arg(*app, unsigned);
        char buf[43];
        char *p = buf + sizeof buf;
        do
            *--p = (m&0x7) + '0';
        while ((m>>= 3) != 0);
        Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
            width, precision);
    }
    static void cvt_x(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        unsigned m = va_arg(*app, unsigned);
        char buf[43];
        char *p = buf + sizeof buf;
        do
            *--p = "0123456789abcdef"[m&0xf];
        while ((m>>= 4) != 0);
        Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
            width, precision);
    }
    static void cvt_p(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        unsigned long m = (unsigned long)va_arg(*app, void*);
        char buf[43];
        char *p = buf + sizeof buf;
        precision = INT_MIN;
        do
            *--p = "0123456789abcdef"[m&0xf];
        while ((m>>= 4) != 0);
        Fmt_putd(p, (buf + sizeof buf) - p, put, cl, flags,
            width, precision);
    }
    static void cvt_c(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        if (width == INT_MIN)
            width = 0;
        if (width < 0) {
            flags['-'] = 1;
            width = -width;
        }
        if (!flags['-'])
            pad(width - 1' ');
        put((unsigned char)va_arg(*app, int), cl);
        if ( flags['-'])
            pad(width - 1' ');
    }
    static void cvt_f(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        char buf[DBL_MAX_10_EXP+1+1+99+1];
        if (precision < 0)
            precision = 6;
        if (code == 'g' && precision == 0)
            precision = 1;
        {
            static char fmt[] = "%.dd?";
            assert(precision <= 99);
            fmt[4] = code;
            fmt[3] =      precision%10 + '0';
            fmt[2] = (precision/10)%10 + '0';
            sprintf(buf, fmt, va_arg(*app, double));
        }
        Fmt_putd(buf, strlen(buf), put, cl, flags,
            width, precision);
    }
    const Except_T Fmt_Overflow = { "Formatting Overflow" };
    static T cvt[256] = {
     /*   0-  7 */ 0,     00,     0,     0,     0,     0,     0,
     /*   8- 15 */ 0,     00,     0,     0,     0,     0,     0,
     /*  16- 23 */ 0,     00,     0,     0,     0,     0,     0,
     /*  24- 31 */ 0,     00,     0,     0,     0,     0,     0,
     /*  32- 39 */ 0,     00,     0,     0,     0,     0,     0,
     /*  40- 47 */ 0,     00,     0,     0,     0,     0,     0,
     /*  48- 55 */ 0,     00,     0,     0,     0,     0,     0,
     /*  56- 63 */ 0,     00,     0,     0,     0,     0,     0,
     /*  64- 71 */ 0,     00,     0,     0,     0,     0,     0,
     /*  72- 79 */ 0,     00,     0,     0,     0,     0,     0,
     /*  80- 87 */ 0,     00,     0,     0,     0,     0,     0,
     /*  88- 95 */ 0,     00,     0,     0,     0,     0,     0,
     /*  96-103 */ 0,     00, cvt_c, cvt_d, cvt_f, cvt_f, cvt_f,
     /* 104-111 */ 0,     00,     0,     0,     0,     0, cvt_o,
     /* 112-119 */ cvt_p, 00, cvt_s,     0, cvt_u,     0,     0,
     /* 120-127 */ cvt_x, 00,     0,     0,     0,     0,     0
    };
    char *Fmt_flags = "-+ 0";
    static int outc(int c, void *cl) {
        FILE *f = cl;
        return putc(c, f);
    }
    static int insert(int c, void *cl) {
        struct buf *p = cl;
        if (p->bp >= p->buf + p->size)
            RAISE(Fmt_Overflow);
        *p->bp++ = c;
        return c;
    }
    static int append(int c, void *cl) {
        struct buf *p = cl;
        if (p->bp >= p->buf + p->size) {
            RESIZE(p->buf, 2*p->size);
            p->bp = p->buf + p->size;
            p->size *= 2;
        }
        *p->bp++ = c;
        return c;
    }
    void Fmt_puts(const char *str, int len,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        assert(str);
        assert(len >= 0);
        assert(flags);
        if (width == INT_MIN)
            width = 0;
        if (width < 0) {
            flags['-'] = 1;
            width = -width;
        }
        if (precision >= 0)
            flags['0'] = 0;
        if (precision >= 0 && precision < len)
            len = precision;
        if (!flags['-'])
            pad(width - len, ' ');
        {
            int i;
            for (i = 0; i < len; i++)
                put((unsigned char)*str++, cl);
        }
        if ( flags['-'])
            pad(width - len, ' ');
    }
    void Fmt_fmt(int put(int c, void *), void *cl,
        const char *fmt, ...) {
        va_list ap;
        va_start(ap, fmt);
        Fmt_vfmt(put, cl, fmt, ap);
        va_end(ap);
    }
    void Fmt_print(const char *fmt, ...) {
        va_list ap;
        va_start(ap, fmt);
        Fmt_vfmt(outc, stdout, fmt, ap);
        va_end(ap);
    }
    void Fmt_fprint(FILE *stream, const char *fmt, ...) {
        va_list ap;
        va_start(ap, fmt);
        Fmt_vfmt(outc, stream, fmt, ap);
        va_end(ap);
    }
    int Fmt_sfmt(char *buf, int size, const char *fmt, ...) {
        va_list ap;
        int len;
        va_start(ap, fmt);
        len = Fmt_vsfmt(buf, size, fmt, ap);
        va_end(ap);
        return len;
    }
    int Fmt_vsfmt(char *buf, int size, const char *fmt,
        va_list ap) {
        struct buf cl;
        assert(buf);
        assert(size > 0);
        assert(fmt);
        cl.buf = cl.bp = buf;
        cl.size = size;
        Fmt_vfmt(insert, &cl, fmt, ap);
        insert(0, &cl);
        return cl.bp - cl.buf - 1;
    }
    char *Fmt_string(const char *fmt, ...) {
        char *str;
        va_list ap;
        assert(fmt);
        va_start(ap, fmt);
        str = Fmt_vstring(fmt, ap);
        va_end(ap);
        return str;
    }
    char *Fmt_vstring(const char *fmt, va_list ap) {
        struct buf cl;
        assert(fmt);
        cl.size = 256;
        cl.buf = cl.bp = ALLOC(cl.size);
        Fmt_vfmt(append, &cl, fmt, ap);
        append(0, &cl);
        return RESIZE(cl.buf, cl.bp - cl.buf);
    }
    void Fmt_vfmt(int put(int c, void *cl), void *cl,
        const char *fmt, va_list ap) {
        assert(put);
        assert(fmt);
        while (*fmt)
            if (*fmt != '%' || *++fmt == '%')
                put((unsigned char)*fmt++, cl);
            else
                {
                    unsigned char c, flags[256];
                    int width = INT_MIN, precision = INT_MIN;
                    memset(flags, '\0'sizeof flags);
                    if (Fmt_flags) {
                        unsigned char c = *fmt;
                        for ( ; c && strchr(Fmt_flags, c); c = *++fmt) {
                            assert(flags[c] < 255);
                            flags[c]++;
                        }
                    }
                    if (*fmt == '*' || isdigit(*fmt)) {
                        int n;
                        if (*fmt == '*') {
                            n = va_arg(ap, int);
                            assert(n != INT_MIN);
                            fmt++;
                        } else
                            for (n = 0; isdigit(*fmt); fmt++) {
                                int d = *fmt - '0';
                                assert(n <= (INT_MAX - d)/10);
                                n = 10*n + d;
                            }
                        width = n;
                    }
                    if (*fmt == '.' && (*++fmt == '*' || isdigit(*fmt))) {
                        int n;
                        if (*fmt == '*') {
                            n = va_arg(ap, int);
                            assert(n != INT_MIN);
                            fmt++;
                        } else
                            for (n = 0; isdigit(*fmt); fmt++) {
                                int d = *fmt - '0';
                                assert(n <= (INT_MAX - d)/10);
                                n = 10*n + d;
                            }
                        precision = n;
                    }
                    c = *fmt++;
                    assert(cvt[c]);
                    (*cvt[c])(c, &ap, put, cl, flags, width, precision);
                }
    }
    T Fmt_register(int code, T newcvt) {
        T old;
        assert(0 < code
            && code < (int)(sizeof (cvt)/sizeof (cvt[0])));
        old = cvt[code];
        cvt[code] = newcvt;
        return old;
    }
    void Fmt_putd(const char *str, int len,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        int sign;
        assert(str);
        assert(len >= 0);
        assert(flags);
        if (width == INT_MIN)
            width = 0;
        if (width < 0) {
            flags['-'] = 1;
            width = -width;
        }
        if (precision >= 0)
            flags['0'] = 0;
        if (len > 0 && (*str == '-' || *str == '+')) {
            sign = *str++;
            len--;
        } else if (flags['+'])
            sign = '+';
        else if (flags[' '])
            sign = ' ';
        else
            sign = 0;
        { int n;
          if (precision < 0)
              precision = 1;
          if (len < precision)
              n = precision;
          else if (precision == 0 && len == 1 && str[0] == '0')
              n = 0;
          else
              n = len;
          if (sign)
              n++;
          if (flags['-']) {
              if (sign)
                put(sign, cl);
          } else if (flags['0']) {
              if (sign)
                put(sign, cl);
              pad(width - n, '0');
          } else {
              pad(width - n, ' ');
              if (sign)
                put(sign, cl);
          }
          pad(precision - len, '0');
          {
              int i;
              for (i = 0; i < len; i++)
                  put((unsigned char)*str++, cl);
          }
          if (flags['-'])
              pad(width - n, ' '); }
    }

     

    str.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/str.doc,v 1.10 1996/06/26 23:02:01 drh Exp $ */
    #ifndef STR_INCLUDED
    #define STR_INCLUDED
    #include <stdarg.h>
    extern char *Str_sub(const char *s, int i, int j);
    extern char *Str_dup(const char *s, int i, int j, int n);
    extern char *Str_cat(const char *s1, int i1, int j1,
        const char *s2, int i2, int j2);
    extern char *Str_catv   (const char *s, ...);
    extern char *Str_reverse(const char *s, int i, int j);
    extern char *Str_map    (const char *s, int i, int j,
        const char *fromconst char *to);
    extern int Str_pos(const char *s, int i);
    extern int Str_len(const char *s, int i, int j);
    extern int Str_cmp(const char *s1, int i1, int j1,
        const char *s2, int i2, int j2);
    extern int Str_chr  (const char *s, int i, int j, int c);
    extern int Str_rchr (const char *s, int i, int j, int c);
    extern int Str_upto (const char *s, int i, int j,
        const char *set);
    extern int Str_rupto(const char *s, int i, int j,
        const char *set);
    extern int Str_find (const char *s, int i, int j,
        const char *str);
    extern int Str_rfind(const char *s, int i, int j,
        const char *str);
    extern int Str_any   (const char *s, int i,
        const char *set);
    extern int Str_many  (const char *s, int i, int j,
        const char *set);
    extern int Str_rmany (const char *s, int i, int j,
        const char *set);
    extern int Str_match (const char *s, int i, int j,
        const char *str);
    extern int Str_rmatch(const char *s, int i, int j,
        const char *str);
    extern void Str_fmt(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision);
    #undef T
    #endif

     

    str.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/str.doc,v 1.10 1996/06/26 23:02:01 drh Exp $";
    #include <string.h>
    #include <limits.h>
    #include "assert.h"
    #include "fmt.h"
    #include "str.h"
    #include "mem.h"
    #define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1)
    #define convert(s, i, j) do { int len; \
        assert(s); len = strlen(s); \
        i = idx(i, len); j = idx(j, len); \
        if (i > j) { int t = i; i = j; j = t; } \
        assert(i >= 0 && j <= len); } while (0)
    char *Str_sub(const char *s, int i, int j) {
        char *str, *p;
        convert(s, i, j);
        p = str = ALLOC(j - i + 1);
        while (i < j)
            *p++ = s[i++];
        *p = '\0';
        return str;
    }
    char *Str_dup(const char *s, int i, int j, int n) {
        int k;
        char *str, *p;
        assert(n >= 0);
        convert(s, i, j);
        p = str = ALLOC(n*(j - i) + 1);
        if (j - i > 0)
            while (n-- > 0)
                for (k = i; k < j; k++)
                    *p++ = s[k];
        *p = '\0';
        return str;
    }
    char *Str_reverse(const char *s, int i, int j) {
        char *str, *p;
        convert(s, i, j);
        p = str = ALLOC(j - i + 1);
        while (j > i)
            *p++ = s[--j];
        *p = '\0';
        return str;
    }
    char *Str_cat(const char *s1, int i1, int j1,
                  const char *s2, int i2, int j2) {
        char *str, *p;
        convert(s1, i1, j1);
        convert(s2, i2, j2);
        p = str = ALLOC(j1 - i1 + j2 - i2 + 1);
        while (i1 < j1)
            *p++ = s1[i1++];
        while (i2 < j2)
            *p++ = s2[i2++];
        *p = '\0';
        return str;
    }
    char *Str_catv(const char *s, ...) {
        char *str, *p;
        const char *save = s;
        int i, j, len = 0;
        va_list ap;
        va_start(ap, s);
        while (s) {
            i = va_arg(ap, int);
            j = va_arg(ap, int);
            convert(s, i, j);
            len += j - i;
            s = va_arg(ap, const char *);
        }
        va_end(ap);
        p = str = ALLOC(len + 1);
        s = save;
        va_start(ap, s);
        while (s) {
            i = va_arg(ap, int);
            j = va_arg(ap, int);
            convert(s, i, j);
            while (i < j)
                *p++ = s[i++];
            s = va_arg(ap, const char *);
        }
        va_end(ap);
        *p = '\0';
        return str;
    }
    char *Str_map(const char *s, int i, int j,
        const char *fromconst char *to) {
        static char map[256] = { 0 };
        if (from && to) {
            unsigned c;
            for (c = 0; c < sizeof map; c++)
                map[c] = c;
            while (*from && *to)
                map[(unsigned char)*from++] = *to++;
            assert(*from == 0 && *to == 0);
        } else {
            assert(from == NULL && to == NULL && s);
            assert(map['a']);
        }
        if (s) {
            char *str, *p;
            convert(s, i, j);
            p = str = ALLOC(j - i + 1);
            while (i < j)
                *p++ = map[(unsigned char)s[i++]];
            *p = '\0';
            return str;
        } else
            return NULL;
    }
    int Str_pos(const char *s, int i) {
        int len;
        assert(s);
        len = strlen(s);
        i = idx(i, len);
        assert(i >= 0 && i <= len);
        return i + 1;
    }
    int Str_len(const char *s, int i, int j) {
        convert(s, i, j);
        return j - i;
    }
    int Str_cmp(const char *s1, int i1, int j1,
        const char *s2, int i2, int j2) {
        convert(s1, i1, j1);
        convert(s2, i2, j2);
        s1 += i1;
        s2 += i2;
        if (j1 - i1 < j2 - i2) {
            int cond = strncmp(s1, s2, j1 - i1);
            return cond == 0 ? -1 : cond;
        } else if (j1 - i1 > j2 - i2) {
            int cond = strncmp(s1, s2, j2 - i2);
            return cond == 0 ? +1 : cond;
        } else
            return strncmp(s1, s2, j1 - i1);
    }
    int Str_chr(const char *s, int i, int j, int c) {
        convert(s, i, j);
        for ( ; i < j; i++)
            if (s[i] == c)
                return i + 1;
        return 0;
    }
    int Str_rchr(const char *s, int i, int j, int c) {
        convert(s, i, j);
        while (j > i)
            if (s[--j] == c)
                return j + 1;
        return 0;
    }
    int Str_upto(const char *s, int i, int j,
        const char *set) {
        assert(set);
        convert(s, i, j);
        for ( ; i < j; i++)
            if (strchr(set, s[i]))
                return i + 1;
        return 0;
    }
    int Str_rupto(const char *s, int i, int j,
        const char *set) {
        assert(set);
        convert(s, i, j);
        while (j > i)
            if (strchr(set, s[--j]))
                return j + 1;
        return 0;
    }
    int Str_find(const char *s, int i, int j,
        const char *str) {
        int len;
        convert(s, i, j);
        assert(str);
        len = strlen(str);
        if (len == 0)
            return i + 1;
        else if (len == 1) {
            for ( ; i < j; i++)
                if (s[i] == *str)
                    return i + 1;
        } else
            for ( ; i + len <= j; i++)
                if ((strncmp(&s[i], str, len) == 0))
                    return i + 1;
        return 0;
    }
    int Str_rfind(const char *s, int i, int j,
        const char *str) {
        int len;
        convert(s, i, j);
        assert(str);
        len = strlen(str);
        if (len == 0)
            return j + 1;
        else if (len == 1) {
            while (j > i)
                if (s[--j] == *str)
                    return j + 1;
        } else
            for ( ; j - len >= i; j--)
                if (strncmp(&s[j-len], str, len) == 0)
                    return j - len + 1;
        return 0;
    }
    int Str_any(const char *s, int i, const char *set) {
        int len;
        assert(s);
        assert(set);
        len = strlen(s);
        i = idx(i, len);
        assert(i >= 0 && i <= len);
        if (i < len && strchr(set, s[i]))
            return i + 2;
        return 0;
    }
    int Str_many(const char *s, int i, int j,
        const char *set) {
        assert(set);
        convert(s, i, j);
        if (i < j && strchr(set, s[i])) {
            do
                i++;
            while (i < j && strchr(set, s[i]));
            return i + 1;
        }
        return 0;
    }
    int Str_rmany(const char *s, int i, int j,
        const char *set) {
        assert(set);
        convert(s, i, j);
        if (j > i && strchr(set, s[j-1])) {
            do
                --j;
            while (j >= i && strchr(set, s[j]));
            return j + 2;
        }
        return 0;
    }
    int Str_match(const char *s, int i, int j,
        const char *str) {
        int len;
        convert(s, i, j);
        assert(str);
        len = strlen(str);
        if (len == 0)
            return i + 1
        else if (len == 1) {
            if (i < j && s[i] == *str)
                return i + 2;
        } else if (i + len <= j && (strncmp(&s[i], str, len) == 0))
            return i + len + 1;
        return 0;
    }
    int Str_rmatch(const char *s, int i, int j,
        const char *str) {
        int len;
        convert(s, i, j);
        assert(str);
        len = strlen(str);
        if (len == 0)
            return j + 1;
        else if (len == 1) {
            if (j > i && s[j-1] == *str)
                return j;
        } else if (j - len >= i
        && strncmp(&s[j-len], str, len) == 0)
            return j - len + 1;
        return 0;
    }
    void Str_fmt(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        char *s;
        int i, j;
        assert(app && flags);
        s = va_arg(*app, char *);
        i = va_arg(*app, int);
        j = va_arg(*app, int);
        convert(s, i, j);
        Fmt_puts(s + i, j - i, put, cl, flags,
            width, precision);
    }

     

    ids.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/str.doc,v 1.10 1996/06/26 23:02:01 drh Exp $";
    #include <stdlib.h>
    #include <stdio.h>
    #include "fmt.h"
    #include "str.h"
    int main(int argc, char *argv[]) {
        char line[512];
        static char set[] = "0123456789_"
            "abcdefghijklmnopqrstuvwxyz"
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Fmt_register('S', Str_fmt);
        while (fgets(line, sizeof line, stdin) != NULL) {
            int i = 1, j;
            while ((i = Str_upto(line, i, 0, &set[10])) > 0){
                j = Str_many(line, i, 0set);
                Fmt_print("%S\n", line, i, j);
                i = j;
            }
        }
        return EXIT_SUCCESS;
    }

     

    text.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/text.doc,v 1.10 1996/06/26 23:02:01 drh Exp $ */
    #ifndef TEXT_INCLUDED
    #define TEXT_INCLUDED
    #include <stdarg.h>
    #define T Text_T
    typedef struct T {
        int len;
        const char *str;
    } T;
    typedef struct Text_save_T *Text_save_T;
    extern const T Text_cset;
    extern const T Text_ascii;
    extern const T Text_ucase;
    extern const T Text_lcase;
    extern const T Text_digits;
    extern const T Text_null;
    extern T     Text_put(const char *str);
    extern char *Text_get(char *str, int size, T s);
    extern T     Text_box(const char *str, int len);
    extern T Text_sub(T s, int i, int j);
    extern int Text_pos(T s, int i);
    extern T Text_cat    (T s1, T s2);
    extern T Text_dup    (T s, int n);
    extern T Text_reverse(T s);
    extern T Text_map(T s, const T *fromconst T *to);
    extern int Text_cmp(T s1, T s2);
    extern int Text_chr  (T s, int i, int j, int c);
    extern int Text_rchr (T s, int i, int j, int c);
    extern int Text_upto (T s, int i, int j, T set);
    extern int Text_rupto(T s, int i, int j, T set);
    extern int Text_any  (T s, int i, T set);
    extern int Text_many (T s, int i, int j, T set);
    extern int Text_rmany(T s, int i, int j, T set);
    extern int Text_find  (T s, int i, int j, T str);
    extern int Text_rfind (T s, int i, int j, T str);
    extern int Text_match (T s, int i, int j, T str);
    extern int Text_rmatch(T s, int i, int j, T str);
    extern void Text_fmt(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision);
    extern Text_save_T Text_save(void);
    extern void        Text_restore(Text_save_T *save);
    #undef T
    #endif

     

    text.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/text.doc,v 1.10 1996/06/26 23:02:01 drh Exp $";
    #include <string.h>
    #include <limits.h>
    #include "assert.h"
    #include "fmt.h"
    #include "text.h"
    #include "mem.h"
    #define T Text_T
    #define idx(i, len) ((i) <= 0 ? (i) + (len) : (i) - 1)
    #define isatend(s, n) ((s).str+(s).len == current->avail\
        && current->avail + (n) <= current->limit)
    #define equal(s, i, t) \
        (memcmp(&(s).str[i], (t).str, (t).len) == 0)
    struct Text_save_T {
        struct chunk *current;
        char *avail;
    };
    static char cset[] =
        "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
        "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
        "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
        "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
        "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
        "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
        "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
        "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
        "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
        "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
        "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
        "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
        "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
        "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
        "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
        "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
        ;
    const T Text_cset   = { 256, cset };
    const T Text_ascii  = { 127, cset };
    const T Text_ucase  = {  26, cset + 'A' };
    const T Text_lcase  = {  26, cset + 'a' };
    const T Text_digits = {  10, cset + '0' };
    const T Text_null   = {   0, cset };
    static struct chunk {
        struct chunk *link;
        char *avail;
        char *limit;
    } head = { NULL, NULL, NULL }, *current = &head;
    static char *alloc(int len) {
        assert(len >= 0);
        if (current->avail + len > current->limit) {
            current = current->link = 
                ALLOC(sizeof (*current) + 10*1024 + len);
            current->avail = (char *)(current + 1);
            current->limit = current->avail + 10*1024 + len;
            current->link = NULL;
        }
        current->avail += len;
        return current->avail - len;
    }
    int Text_pos(T s, int i) {
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        assert(i >= 0 && i <= s.len);
        return i + 1;
    }
    T Text_box(const char *str, int len) {
        T text;
        assert(str);
        assert(len >= 0);
        text.str = str;
        text.len = len;
        return text;
    }
    T Text_sub(T s, int i, int j) {
        T text;
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        text.len = j - i;
        text.str = s.str + i;
        return text;
    }
    T Text_put(const char *str) {
        T text;
        assert(str);
        text.len = strlen(str);
        text.str = memcpy(alloc(text.len), str, text.len);
        return text;
    }
    char *Text_get(char *str, int size, T s) {
        assert(s.len >= 0 && s.str);
        if (str == NULL)
            str = ALLOC(s.len + 1);
        else
            assert(size >= s.len + 1);
        memcpy(str, s.str, s.len);
        str[s.len] = '\0';
        return str;
    }
    T Text_dup(T s, int n) {
        assert(s.len >= 0 && s.str);
        assert(n >= 0);
        if (n == 0 || s.len == 0)
            return Text_null;
        if (n == 1)
            return s;
        {
            T text;
            char *p;
            text.len = n*s.len;
            if (isatend(s, text.len - s.len)) {
                text.str = s.str;
                p = alloc(text.len - s.len);
                n--;
            } else
                text.str = p = alloc(text.len);
            for ( ; n-- > 0; p += s.len)
                memcpy(p, s.str, s.len);
            return text;
        }
    }
    T Text_cat(T s1, T s2) {
        assert(s1.len >= 0 && s1.str);
        assert(s2.len >= 0 && s2.str);
        if (s1.len == 0)
            return s2;
        if (s2.len == 0)
            return s1;
        if (s1.str + s1.len == s2.str) {
            s1.len += s2.len;
            return s1;
        }
        {
            T text;
            text.len = s1.len + s2.len;
            if (isatend(s1, s2.len)) {
                text.str = s1.str;
                memcpy(alloc(s2.len), s2.str, s2.len);
            } else {
                char *p;
                text.str = p = alloc(s1.len + s2.len);
                memcpy(p,          s1.str, s1.len);
                memcpy(p + s1.len, s2.str, s2.len);
            }
            return text;
        } 
    }
    T Text_reverse(T s) {
        assert(s.len >= 0 && s.str);
        if (s.len == 0)
            return Text_null;
        else if (s.len == 1)
            return s;
        else {
            T text;
            char *p;
            int i = s.len;
            text.len = s.len;
            text.str = p = alloc(s.len);
            while (--i >= 0)
                *p++ = s.str[i];
            return text;
        }
    }
    T Text_map(T s, const T *fromconst T *to) {
        static char map[256];
        static int inited = 0;
        assert(s.len >= 0 && s.str);
        if (from && to) {
            int k;
            for (k = 0; k < (int)sizeof map; k++)
                map[k] = k;
            assert(from->len == to->len);
            for (k = 0; k < from->len; k++)
                map[from->str[k]] = to->str[k];
            inited = 1;
        } else {
            assert(from == NULL && to == NULL);
            assert(inited);
        }
        if (s.len == 0)
            return Text_null;
        else {
            T text;
            int i;
            char *p;
            text.len = s.len;
            text.str = p = alloc(s.len);
            for (i = 0; i < s.len; i++)
                *p++ = map[s.str[i]];
            return text;
        }
    }
    int Text_cmp(T s1, T s2) {
        assert(s1.len >= 0 && s1.str);
        assert(s2.len >= 0 && s2.str);
        if (s1.str == s2.str)
            return s1.len - s2.len;
        else if (s1.len < s2.len) {
            int cond = memcmp(s1.str, s2.str, s1.len);
            return cond == 0 ? -1 : cond;
        } else if (s1.len > s2.len) {
            int cond = memcmp(s1.str, s2.str, s2.len);
            return cond == 0 ? +1 : cond;
        } else
            return memcmp(s1.str, s2.str, s1.len);
    }
    Text_save_T Text_save(void) {
        Text_save_T save;
        NEW(save);
        save->current = current;
        save->avail = current->avail;
        alloc(1);
        return save;
    }
    void Text_restore(Text_save_T *save) {
        struct chunk *p, *q;
        assert(save && *save);
        current = (*save)->current;
        current->avail = (*save)->avail;
        FREE(*save);
        for (p = current->link; p; p = q) {
            q = p->link;
            FREE(p);
        }
        current->link = NULL;
    }
    int Text_chr(T s, int i, int j, int c) {
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        for ( ; i < j; i++)
            if (s.str[i] == c)
                return i + 1;
        return 0;
    }
    int Text_rchr(T s, int i, int j, int c) {
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        while (j > i)
            if (s.str[--j] == c)
                return j + 1;
        return 0;
    }
    int Text_upto(T s, int i, int j, T set) {
        assert(set.len >= 0 && set.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        for ( ; i < j; i++)
            if (memchr(set.str, s.str[i], set.len))
                return i + 1;
        return 0;
    }
    int Text_rupto(T s, int i, int j, T set) {
        assert(set.len >= 0 && set.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        while (j > i)
            if (memchr(set.str, s.str[--j], set.len))
                return j + 1;
        return 0;
    }
    int Text_find(T s, int i, int j, T str) {
        assert(str.len >= 0 && str.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        if (str.len == 0)
            return i + 1;
        else if (str.len == 1) {
            for ( ; i < j; i++)
                if (s.str[i] == *str.str)
                    return i + 1;
        } else
            for ( ; i + str.len <= j; i++)
                if (equal(s, i, str))
                    return i + 1;
        return 0;
    }
    int Text_rfind(T s, int i, int j, T str) {
        assert(str.len >= 0 && str.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        if (str.len == 0)
            return j + 1;
        else if (str.len == 1) {
            while (j > i)
                if (s.str[--j] == *str.str)
                    return j + 1;
        } else
            for ( ; j - str.len >= i; j--)
                if (equal(s, j - str.len, str))
                    return j - str.len + 1;
        return 0;
    }
    int Text_any(T s, int i, T set) {
        assert(s.len >= 0 && s.str);
        assert(set.len >= 0 && set.str);
        i = idx(i, s.len);
        assert(i >= 0 && i <= s.len);
        if (i < s.len && memchr(set.str, s.str[i], set.len))
            return i + 2;
        return 0;
    }
    int Text_many(T s, int i, int j, T set) {
        assert(set.len >= 0 && set.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        if (i < j && memchr(set.str, s.str[i], set.len)) {
            do
                i++;
            while (i < j
            && memchr(set.str, s.str[i], set.len));
            return i + 1;
        }
        return 0;
    }
    int Text_rmany(T s, int i, int j, T set) {
        assert(set.len >= 0 && set.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        if (j > i && memchr(set.str, s.str[j-1], set.len)) {
            do
                --j;
            while (j >= i
            && memchr(set.str, s.str[j], set.len));
            return j + 2;
        }
        return 0;
    }
    int Text_match(T s, int i, int j, T str) {
        assert(str.len >= 0 && str.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        if (str.len == 0)
            return i + 1;
        else if (str.len == 1) {
            if (i < j && s.str[i] == *str.str)
                return i + 2;
        } else if (i + str.len <= j && equal(s, i, str))
            return i + str.len + 1;
        return 0;
    }
    int Text_rmatch(T s, int i, int j, T str) {
        assert(str.len >= 0 && str.str);
        assert(s.len >= 0 && s.str);
        i = idx(i, s.len);
        j = idx(j, s.len);
        if (i > j) { int t = i; i = j; j = t; }
        assert(i >= 0 && j <= s.len);
        if (str.len == 0)
            return j + 1;
        else if (str.len == 1) {
            if (j > i && s.str[j-1] == *str.str)
                return j;
        } else if (j - str.len >= i
        && equal(s, j - str.len, str))
            return j - str.len + 1;
        return 0;
    }
    void Text_fmt(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        T *s;
        assert(app && flags);
        s = va_arg(*app, T*);
        assert(s && s->len >= 0 && s->str);
        Fmt_puts(s->str, s->len, put, cl, flags,
            width, precision);
    }

     

    xp.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/xp.doc,v 1.10 1996/06/26 23:02:01 drh Exp $ */
    #ifndef XP_INCLUDED
    #define XP_INCLUDED
    #define T XP_T
    typedef unsigned char *T;
    extern int XP_add(int n, T z, T x, T y, int carry);
    extern int XP_sub(int n, T z, T x, T y, int borrow);
    extern int XP_mul(T z, int n, T x, int m, T y);
    extern int XP_div(int n, T q, T x, int m, T y, T r,T tmp);
    extern int XP_sum     (int n, T z, T x, int y);
    extern int XP_diff    (int n, T z, T x, int y);
    extern int XP_product (int n, T z, T x, int y);
    extern int XP_quotient(int n, T z, T x, int y);
    extern int XP_neg(int n, T z, T x, int carry);
    extern int XP_cmp(int n, T x, T y);
    extern void XP_lshift(int n, T z, int m, T x,
        int s, int fill);
    extern void XP_rshift(int n, T z, int m, T x,
        int s, int fill);
    extern int           XP_length (int n, T x);
    extern unsigned long XP_fromint(int n, T z,
        unsigned long u);
    extern unsigned long XP_toint  (int n, T x);
    extern int   XP_fromstr(int n, T z, const char *str,
        int basechar **end);
    extern char *XP_tostr  (char *str, int size, int base,
        int n, T x);
    #undef T
    #endif

     

    xp.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/xp.doc,v 1.10 1996/06/26 23:02:01 drh Exp $";
    #include <ctype.h>
    #include <string.h>
    #include "assert.h"
    #include "xp.h"
    #define T XP_T
    #define BASE (1<<8)
    static char map[] = {
         0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
        36363636363636,
        10111213141516171819202122,
        23242526272829303132333435,
        363636363636,
        10111213141516171819202122,
        23242526272829303132333435
    };
    unsigned long XP_fromint(int n, T z, unsigned long u) {
        int i = 0;
        do
            z[i++] = u%BASE;
        while ((u /= BASE) > 0 && i < n);
        for ( ; i < n; i++)
            z[i] = 0;
        return u;
    }
    unsigned long XP_toint(int n, T x) {
        unsigned long u = 0;
        int i = (int)sizeof u;
        if (i > n)
            i = n;
        while (--i >= 0)
            u = BASE*u + x[i];
        return u;
    }
    int XP_length(int n, T x) {
        while (n > 1 && x[n-1] == 0)
            n--;
        return n;
    }
    int XP_add(int n, T z, T x, T y, int carry) {
        int i;
        for (i = 0; i < n; i++) {
            carry += x[i] + y[i];
            z[i] = carry%BASE;
            carry /= BASE;
        }
        return carry;
    }
    int XP_sub(int n, T z, T x, T y, int borrow) {
        int i;
        for (i = 0; i < n; i++) {
            int d = (x[i] + BASE) - borrow - y[i];
            z[i] = d%BASE;
            borrow = 1 - d/BASE;
        }
        return borrow;
    }
    int XP_sum(int n, T z, T x, int y) {
        int i;
        for (i = 0; i < n; i++) {
            y += x[i];
            z[i] = y%BASE;
            y /= BASE;
        }
        return y;
    }
    int XP_diff(int n, T z, T x, int y) {
        int i;
        for (i = 0; i < n; i++) {
            int d = (x[i] + BASE) - y;
            z[i] = d%BASE;
            y = 1 - d/BASE;
        }
        return y;
    }
    int XP_neg(int n, T z, T x, int carry) {
        int i;
        for (i = 0; i < n; i++) {
            carry += (unsigned char)~x[i];
            z[i] = carry%BASE;
            carry /= BASE;
        }
        return carry;
    }
    int XP_mul(T z, int n, T x, int m, T y) {
        int i, j, carryout = 0;
        for (i = 0; i < n; i++) {
            unsigned carry = 0;
            for (j = 0; j < m; j++) {
                carry += x[i]*y[j] + z[i+j];
                z[i+j] = carry%BASE;
                carry /= BASE;
            }
            for ( ; j < n + m - i; j++) {
                carry += z[i+j];
                z[i+j] = carry%BASE;
                carry /= BASE;
            }
            carryout |= carry;
        }
        return carryout;
    }
    int XP_product(int n, T z, T x, int y) {
        int i;
        unsigned carry = 0;
        for (i = 0; i < n; i++) {
            carry += x[i]*y;
            z[i] = carry%BASE;
            carry /= BASE;
        }
        return carry;
    }
    int XP_div(int n, T q, T x, int m, T y, T r, T tmp) {
        int nx = n, my = m;
        n = XP_length(n, x);
        m = XP_length(m, y);
        if (m == 1) {
            if (y[0] == 0)
                return 0;
            r[0] = XP_quotient(nx, q, x, y[0]);
            memset(r + 1'\0', my - 1);
        } else if (m > n) {
            memset(q, '\0', nx);
            memcpy(r, x, n);
            memset(r + n, '\0', my - n);
        } else {
            int k;
            unsigned char *rem = tmp, *dq = tmp + n + 1;
            assert(2 <= m && m <= n);
            memcpy(rem, x, n);
            rem[n] = 0;
            for (k = n - m; k >= 0; k--) {
                int qk;
                {
                    int i;
                    assert(2 <= m && m <= k+m && k+m <= n);
                    {
                        int km = k + m;
                        unsigned long y2 = y[m-1]*BASE + y[m-2];
                        unsigned long r3 = rem[km]*(BASE*BASE) +
                            rem[km-1]*BASE + rem[km-2];
                        qk = r3/y2;
                        if (qk >= BASE)
                            qk = BASE - 1;
                    }
                    dq[m] = XP_product(m, dq, y, qk);
                    for (i = m; i > 0; i--)
                        if (rem[i+k] != dq[i])
                            break;
                    if (rem[i+k] < dq[i])
                        dq[m] = XP_product(m, dq, y, --qk);
                }
                q[k] = qk;
                {
                    int borrow;
                    assert(0 <= k && k <= k+m);
                    borrow = XP_sub(m + 1, &rem[k], &rem[k], dq, 0);
                    assert(borrow == 0);
                }
            }
            memcpy(r, rem, m);
            {
                int i;
                for (i = n-m+1; i < nx; i++)
                    q[i] = 0;
                for (i = m; i < my; i++)
                    r[i] = 0;
            }
        }
        return 1;
    }
    int XP_quotient(int n, T z, T x, int y) {
        int i;
        unsigned carry = 0;
        for (i = n - 1; i >= 0; i--) {
            carry = carry*BASE + x[i];
            z[i] = carry/y;
            carry %= y;
        }
        return carry;
    }
    int XP_cmp(int n, T x, T y) {
        int i = n - 1;
        while (i > 0 && x[i] == y[i])
            i--;
        return x[i] - y[i];
    }
    void XP_lshift(int n, T z, int m, T x, int s, int fill) {
        fill = fill ? 0xFF : 0;
        {
            int i, j = n - 1;
            if (n > m)
                i = m - 1;
            else
                i = n - s/8 - 1;
            for ( ; j >= m + s/8; j--)
                z[j] = 0;
            for ( ; i >= 0; i--, j--)
                z[j] = x[i];
            for ( ; j >= 0; j--)
                z[j] = fill;
        }
        s %= 8;
        if (s > 0)
            {
                XP_product(n, z, z, 1<<s);
                z[0] |= fill>>(8-s);
            }
    }
    void XP_rshift(int n, T z, int m, T x, int s, int fill) {
        fill = fill ? 0xFF : 0;
        {
            int i, j = 0;
            for (i = s/8; i < m && j < n; i++, j++)
                z[j] = x[i];
            for ( ; j < n; j++)
                z[j] = fill;
        }
        s %= 8;
        if (s > 0)
            {
                XP_quotient(n, z, z, 1<<s);
                z[n-1] |= fill<<(8-s);
            }
    }
    int XP_fromstr(int n, T z, const char *str,
        int basechar **end) {
        const char *p = str;
        assert(p);
        assert(base >= 2 && base <= 36);
        while (*p && isspace(*p))
            p++;
        if ((*p && isalnum(*p) && map[*p-'0'] < base)) {
            int carry;
            for ( ; (*p && isalnum(*p) && map[*p-'0'] < base); p++) {
                carry = XP_product(n, z, z, base);
                if (carry)
                    break;
                XP_sum(n, z, z, map[*p-'0']);
            }
            if (end)
                *end = (char *)p;
            return carry;
        } else {
            if (end)
                *end = (char *)str;
            return 0;
        }
    }
    char *XP_tostr(char *str, int size, int base,
        int n, T x) {
        int i = 0;
        assert(str);
        assert(base >= 2 && base <= 36);
        do {
            int r = XP_quotient(n, x, x, base);
            assert(i < size);
            str[i++] =
                "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[r];
            while (n > 1 && x[n-1] == 0)
                n--;
        } while (n > 1 || x[0] != 0);
        assert(i < size);
        str[i] = '\0';
        {
            int j;
            for (j = 0; j < --i; j++) {
                char c = str[j];
                str[j] = str[i];
                str[i] = c;
            }
        }
        return str;
    }

     

    ap.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/ap.doc,v 1.11 1996/06/26 23:02:01 drh Exp $ */
    #ifndef AP_INCLUDED
    #define AP_INCLUDED
    #include <stdarg.h>
    #define T AP_T
    typedef struct T *T;
    extern T AP_new    (long int n);
    extern T AP_fromstr(const char *str, int base,
        char **end);
    extern long int AP_toint(T x);
    extern char    *AP_tostr(char *str, int size,
        int base, T x);
    extern void     AP_fmt(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision);
    extern void AP_free(T *z);
    extern T AP_neg(T x);
    extern T AP_add(T x, T y);
    extern T AP_sub(T x, T y);
    extern T AP_mul(T x, T y);
    extern T AP_div(T x, T y);
    extern T AP_mod(T x, T y);
    extern T AP_pow(T x, T y, T p);
    extern T    AP_addi(T x, long int y);
    extern T    AP_subi(T x, long int y);
    extern T    AP_muli(T x, long int y);
    extern T    AP_divi(T x, long int y);
    extern long AP_modi(T x, long int y);
    extern T AP_lshift(T x, int s);
    extern T AP_rshift(T x, int s);
    extern int AP_cmp (T x, T y);
    extern int AP_cmpi(T x, long int y);
    #undef T
    #endif

     

    ap.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/ap.doc,v 1.11 1996/06/26 23:02:01 drh Exp $";
    #include <ctype.h>
    #include <limits.h>
    #include <stdlib.h>
    #include <string.h>
    #include "assert.h"
    #include "ap.h"
    #include "fmt.h"
    #include "xp.h"
    #include "mem.h"
    #define T AP_T
    struct T {
        int sign;
        int ndigits;
        int size;
        XP_T digits;
    };
    #define iszero(x) ((x)->ndigits==1 && (x)->digits[0]==0)
    #define maxdigits(x,y) ((x)->ndigits > (y)->ndigits ? \
        (x)->ndigits : (y)->ndigits)
    #define isone(x) ((x)->ndigits==1 && (x)->digits[0]==1)
    static T normalize(T z, int n);
    static int cmp(T x, T y);
    static T mk(int size) {
        T z = CALLOC(1sizeof (*z) + size);
        assert(size > 0);
        z->sign = 1;
        z->size = size;
        z->ndigits = 1;
        z->digits = (XP_T)(z + 1);
        return z;
    }
    static T set(T z, long int n) {
        if (n == LONG_MIN)
            XP_fromint(z->size, z->digits, LONG_MAX + 1UL);
        else if (n < 0)
            XP_fromint(z->size, z->digits, -n);
        else
            XP_fromint(z->size, z->digits, n);
        z->sign = n < 0 ? -1 : 1;
        return normalize(z, z->size);
    }
    static T normalize(T z, int n) {
        z->ndigits = XP_length(n, z->digits);
        return z;
    }
    static T add(T z, T x, T y) {
        int n = y->ndigits;
        if (x->ndigits < n)
            return add(z, y, x);
        else if (x->ndigits > n) {
            int carry = XP_add(n, z->digits, x->digits,
                y->digits, 0);
            z->digits[z->size-1] = XP_sum(x->ndigits - n,
                &z->digits[n], &x->digits[n], carry);
        } else
            z->digits[n] = XP_add(n, z->digits, x->digits,
                y->digits, 0);
        return normalize(z, z->size);
    }
    static T sub(T z, T x, T y) {
        int borrow, n = y->ndigits;
        borrow = XP_sub(n, z->digits, x->digits,
            y->digits, 0);
        if (x->ndigits > n)
            borrow = XP_diff(x->ndigits - n, &z->digits[n],
                &x->digits[n], borrow);
        assert(borrow == 0);
        return normalize(z, z->size);
    }
    static T mulmod(T x, T y, T p) {
        T z, xy = AP_mul(x, y);
        z = AP_mod(xy, p);
        AP_free(&xy);
        return z;
    }
    static int cmp(T x, T y) {
        if (x->ndigits != y->ndigits)
            return x->ndigits - y->ndigits;
        else
            return XP_cmp(x->ndigits, x->digits, y->digits);
    }
    T AP_new(long int n) {
        return set(mk(sizeof (long int)), n);
    }
    void AP_free(T *z) {
        assert(z && *z);
        FREE(*z);
    }
    T AP_neg(T x) {
        T z;
        assert(x);
        z = mk(x->ndigits);
        memcpy(z->digits, x->digits, x->ndigits);
        z->ndigits = x->ndigits;
        z->sign = iszero(z) ? 1 : -x->sign;
        return z;
    }
    T AP_mul(T x, T y) {
        T z;
        assert(x);
        assert(y);
        z = mk(x->ndigits + y->ndigits);
        XP_mul(z->digits, x->ndigits, x->digits, y->ndigits,
            y->digits);
        normalize(z, z->size);
        z->sign = iszero(z)
            || ((x->sign^y->sign) == 0) ? 1 : -1;
        return z;
    }
    T AP_add(T x, T y) {
        T z;
        assert(x);
        assert(y);
        if (((x->sign^y->sign) == 0)) {
            z = add(mk(maxdigits(x,y) + 1), x, y);
            z->sign = iszero(z) ? 1 : x->sign;
        } else
            if (cmp(x, y) > 0) {
                z = sub(mk(x->ndigits), x, y);
                z->sign = iszero(z) ? 1 : x->sign;
            }
            else {
                z = sub(mk(y->ndigits), y, x);
                z->sign = iszero(z) ? 1 : -x->sign;
            }
        return z;
    }
    T AP_sub(T x, T y) {
        T z;
        assert(x);
        assert(y);
        if (!((x->sign^y->sign) == 0)) {
            z = add(mk(maxdigits(x,y) + 1), x, y);
            z->sign = iszero(z) ? 1 : x->sign;
        } else
            if (cmp(x, y) > 0) {
                z = sub(mk(x->ndigits), x, y);
                z->sign = iszero(z) ? 1 : x->sign;
            } else {
                z = sub(mk(y->ndigits), y, x);
                z->sign = iszero(z) ? 1 : -x->sign;
            }
        return z;
    }
    T AP_div(T x, T y) {
        T q, r;
        assert(x);
        assert(y);
        assert(!iszero(y));
        q = mk(x->ndigits);
        r = mk(y->ndigits);
        {
            XP_T tmp = ALLOC(x->ndigits + y->ndigits + 2);
            XP_div(x->ndigits, q->digits, x->digits,
                y->ndigits, y->digits, r->digits, tmp);
            FREE(tmp);
        }
        normalize(q, q->size);
        normalize(r, r->size);
        q->sign = iszero(q)
            || ((x->sign^y->sign) == 0) ? 1 : -1;
        if (!((x->sign^y->sign) == 0) && !iszero(r)) {
            int carry = XP_sum(q->size, q->digits,
                q->digits, 1);
            assert(carry == 0);
            normalize(q, q->size);
        }
        AP_free(&r);
        return q;
    }
    T AP_mod(T x, T y) {
        T q, r;
        assert(x);
        assert(y);
        assert(!iszero(y));
        q = mk(x->ndigits);
        r = mk(y->ndigits);
        {
            XP_T tmp = ALLOC(x->ndigits + y->ndigits + 2);
            XP_div(x->ndigits, q->digits, x->digits,
                y->ndigits, y->digits, r->digits, tmp);
            FREE(tmp);
        }
        normalize(q, q->size);
        normalize(r, r->size);
        q->sign = iszero(q)
            || ((x->sign^y->sign) == 0) ? 1 : -1;
        if (!((x->sign^y->sign) == 0) && !iszero(r)) {
            int borrow = XP_sub(r->size, r->digits,
                y->digits, r->digits, 0);
            assert(borrow == 0);
            normalize(r, r->size);
        }
        AP_free(&q);
        return r;
    }
    T AP_pow(T x, T y, T p) {
        T z;
        assert(x);
        assert(y);
        assert(y->sign == 1);
        assert(!p || p->sign==1 && !iszero(p) && !isone(p));
        if (iszero(x))
            return AP_new(0);
        if (iszero(y))
            return AP_new(1);
        if (isone(x))
            return AP_new((((y)->digits[0]&1) == 0) ? 1 : x->sign);
        if (p)
            if (isone(y))
                z = AP_mod(x, p);
            else {
                T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, p);
                z = mulmod(t, t, p);
                AP_free(&y2);
                AP_free(&t);
                if (!(((y)->digits[0]&1) == 0)) {
                    z = mulmod(y2 = AP_mod(x, p), t = z, p);
                    AP_free(&y2);
                    AP_free(&t);
                }
            }
        else
            if (isone(y))
                z = AP_addi(x, 0);
            else {
                T y2 = AP_rshift(y, 1), t = AP_pow(x, y2, NULL);
                z = AP_mul(t, t);
                AP_free(&y2);
                AP_free(&t);
                if (!(((y)->digits[0]&1) == 0)) {
                    z = AP_mul(x, t = z);
                    AP_free(&t);
                }
            }
        return z;
    }
    int AP_cmp(T x, T y) {
        assert(x);
        assert(y);
        if (!((x->sign^y->sign) == 0))
            return x->sign;
        else if (x->sign == 1)
            return cmp(x, y);
        else
            return cmp(y, x);
    }
    T AP_addi(T x, long int y) {
        unsigned char d[sizeof (unsigned long)];
        struct T t;
        t.size = sizeof d;
        t.digits = d;
        return AP_add(x, set(&t, y));
    }
    T AP_subi(T x, long int y) {
        unsigned char d[sizeof (unsigned long)];
        struct T t;
        t.size = sizeof d;
        t.digits = d;
        return AP_sub(x, set(&t, y));
    }
    T AP_muli(T x, long int y) {
        unsigned char d[sizeof (unsigned long)];
        struct T t;
        t.size = sizeof d;
        t.digits = d;
        return AP_mul(x, set(&t, y));
    }
    T AP_divi(T x, long int y) {
        unsigned char d[sizeof (unsigned long)];
        struct T t;
        t.size = sizeof d;
        t.digits = d;
        return AP_div(x, set(&t, y));
    }
    int AP_cmpi(T x, long int y) {
        unsigned char d[sizeof (unsigned long)];
        struct T t;
        t.size = sizeof d;
        t.digits = d;
        return AP_cmp(x, set(&t, y));
    }
    long int AP_modi(T x, long int y) {
        long int rem;
        T r;
        unsigned char d[sizeof (unsigned long)];
        struct T t;
        t.size = sizeof d;
        t.digits = d;
        r = AP_mod(x, set(&t, y));
        rem = XP_toint(r->ndigits, r->digits);
        AP_free(&r);
        return rem;
    }
    T AP_lshift(T x, int s) {
        T z;
        assert(x);
        assert(s >= 0);
        z = mk(x->ndigits + ((s+7)&~7)/8);
        XP_lshift(z->size, z->digits, x->ndigits,
            x->digits, s, 0);
        z->sign = x->sign;
        return normalize(z, z->size);
    }
    T AP_rshift(T x, int s) {
        assert(x);
        assert(s >= 0);
        if (s >= 8*x->ndigits)
            return AP_new(0);
        else {
            T z = mk(x->ndigits - s/8);
            XP_rshift(z->size, z->digits, x->ndigits,
                x->digits, s, 0);
            normalize(z, z->size);
            z->sign = iszero(z) ? 1 : x->sign;
            return z;
        }
    }
    long int AP_toint(T x) {
        unsigned long u;
        assert(x);
        u = XP_toint(x->ndigits, x->digits)%(LONG_MAX + 1UL);
        if (x->sign == -1)
            return -(long)u;
        else
            return  (long)u;
    }
    T AP_fromstr(const char *str, int basechar **end) {
        T z;
        const char *p = str;
        char *endp, sign = '\0';
        int carry;
        assert(p);
        assert(base >= 2 && base <= 36);
        while (*p && isspace(*p))
            p++;
        if (*p == '-' || *p == '+')
            sign = *p++;
        {
            const char *start;
            int k, n = 0;
            for ( ; *p == '0' && p[1] == '0'; p++)
                ;
            start = p;
            for ( ; (  '0' <= *p && *p <= '9' && *p < '0' + base
                || 'a' <= *p && *p <= 'z' && *p < 'a' + base - 10
                || 'A' <= *p && *p <= 'Z' && *p < 'A' + base - 10); p++)
                n++;
            for (k = 1; (1<<k) < base; k++)
                ;
            z = mk(((k*n + 7)&~7)/8);
            p = start;
        }
        carry = XP_fromstr(z->size, z->digits, p,
            base, &endp);
        assert(carry == 0);
        normalize(z, z->size);
        if (endp == p) {
            endp = (char *)str;
            z = AP_new(0);
        } else
            z->sign = iszero(z) || sign != '-' ? 1 : -1;
        if (end)
            *end = (char *)endp;
        return z;
    }
    char *AP_tostr(char *str, int size, int base, T x) {
        XP_T q;
        assert(x);
        assert(base >= 2 && base <= 36);
        assert(str == NULL || size > 1);
        if (str == NULL) {
            {
                int k;
                for (k = 5; (1<<k) > base; k--)
                    ;
                size = (8*x->ndigits)/k + 1 + 1;
                if (x->sign == 1)
                    size++;
            }
            str = ALLOC(size);
        }
        q = ALLOC(x->ndigits);
        memcpy(q, x->digits, x->ndigits);
        if (x->sign == -1) {
            str[0] = '-';
            XP_tostr(str + 1, size - 1base, x->ndigits, q);
        } else
            XP_tostr(str, size, base, x->ndigits, q);
        FREE(q);
        return str;
    }
    void AP_fmt(int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision) {
        T x;
        char *buf;
        assert(app && flags);
        x = va_arg(*app, T);
        assert(x);
        buf = AP_tostr(NULL, 010, x);
        Fmt_putd(buf, strlen(buf), put, cl, flags,
            width, precision);
        FREE(buf);
    }

     

    calc.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/ap.doc,v 1.11 1996/06/26 23:02:01 drh Exp $";
    #include <ctype.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "stack.h"
    #include "ap.h"
    #include "fmt.h"
    Stack_T sp;
    AP_T pop(void) {
        if (!Stack_empty(sp))
            return Stack_pop(sp);
        else {
            Fmt_fprint(stderr, "?stack underflow\n");
            return AP_new(0);
        }
    }
    int main(int argc, char *argv[]) {
        int c;
        sp = Stack_new();
        Fmt_register('D', AP_fmt);
        while ((c = getchar()) != EOF)
            switch (c) {
            case ' 'case '\t'case '\n'case '\f'case '\r':
                break;
            case '0'case '1'case '2'case '3'case '4':
            case '5'case '6'case '7'case '8'case '9': {
                char buf[512];
                {
                    int i = 0;
                    for ( ; c != EOF && isdigit(c); c = getchar(), i++)
                        if (i < (int)sizeof (buf) - 1)
                            buf[i] = c;
                    if (i > (int)sizeof (buf) - 1) {
                        i = (int)sizeof (buf) - 1;
                        Fmt_fprint(stderr,
                            "?integer constant exceeds %d digits\n", i);
                    }
                    buf[i] = 0;
                    if (c != EOF)
                        ungetc(c, stdin);
                }
                Stack_push(sp, AP_fromstr(buf, 10, NULL));
                break;
            }
            case '+': {
                AP_T y = pop(), x = pop();
                Stack_push(sp, AP_add(x, y));
                AP_free(&x);
                AP_free(&y);
                break;
            }
            case '-': {
                AP_T y = pop(), x = pop();
                Stack_push(sp, AP_sub(x, y));
                AP_free(&x);
                AP_free(&y);
                break;
            }
            case '*': {
                AP_T y = pop(), x = pop();
                Stack_push(sp, AP_mul(x, y));
                AP_free(&x);
                AP_free(&y);
                break;
            }
            case '/': {
                AP_T y = pop(), x = pop();
                if (AP_cmpi(y, 0) == 0) {
                    Fmt_fprint(stderr, "?/ by 0\n");
                    Stack_push(sp, AP_new(0));
                } else
                    Stack_push(sp, AP_div(x, y));
                AP_free(&x);
                AP_free(&y);
                break;
            }
            case '%': {
                AP_T y = pop(), x = pop();
                if (AP_cmpi(y, 0) == 0) {
                    Fmt_fprint(stderr, "?%% by 0\n");
                    Stack_push(sp, AP_new(0));
                } else
                    Stack_push(sp, AP_mod(x, y));
                AP_free(&x);
                AP_free(&y);
                break;
            }
            case '^': {
                AP_T y = pop(), x = pop();
                if (AP_cmpi(y, 0) <= 0) {
                    Fmt_fprint(stderr, "?nonpositive power\n");
                    Stack_push(sp, AP_new(0));
                } else
                    Stack_push(sp, AP_pow(x, y, NULL));
                AP_free(&x);
                AP_free(&y);
                break;
            }
            case 'd': {
                AP_T x = pop();
                Stack_push(sp, x);
                Stack_push(sp, AP_addi(x, 0));
                break;
            }
            case 'p': {
                AP_T x = pop();
                Fmt_print("%D\n", x);
                Stack_push(sp, x);
                break;
            }
            case 'f':
                if (!Stack_empty(sp)) {
                    Stack_T tmp = Stack_new();
                    while (!Stack_empty(sp)) {
                        AP_T x = pop();
                        Fmt_print("%D\n", x);
                        Stack_push(tmp, x);
                    }
                    while (!Stack_empty(tmp))
                        Stack_push(sp, Stack_pop(tmp));
                    Stack_free(&tmp);
                }
                break;
            case '~': {
                AP_T x = pop();
                Stack_push(sp, AP_neg(x));
                AP_free(&x);
                break;
            }
            case 'c'while (!Stack_empty(sp)) {
                      AP_T x = Stack_pop(sp);
                      AP_free(&x);
                  } break;
            case 'q'while (!Stack_empty(sp)) {
                      AP_T x = Stack_pop(sp);
                      AP_free(&x);
                  }
                  Stack_free(&sp);
                  return EXIT_SUCCESS;
            default:
                if (isprint(c))
                    Fmt_fprint(stderr, "?'%c'", c);
                else
                    Fmt_fprint(stderr, "?'\\%03o'", c);
                Fmt_fprint(stderr, " is unimplemented\n");
                break;
            }
        while (!Stack_empty(sp)) {
            AP_T x = Stack_pop(sp);
            AP_free(&x);
        }
        Stack_free(&sp);
        return EXIT_SUCCESS;
    }

     

    mp.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/mp.doc,v 1.11 1996/06/26 23:02:01 drh Exp $ */
    #ifndef MP_INCLUDED
    #define MP_INCLUDED
    #include <stdarg.h>
    #include <stddef.h>
    #include "except.h"
    #define T MP_T
    typedef unsigned char *T;
    extern const Except_T MP_Overflow;
    extern const Except_T MP_Dividebyzero;
    extern int MP_set(int n);
    extern T MP_new(unsigned long u);
    extern T MP_fromint (T z, long v);
    extern T MP_fromintu(T z, unsigned long u);
    extern unsigned long MP_tointu(T x);
    extern          long MP_toint (T x);
    extern T MP_cvt (int m, T z, T x);
    extern T MP_cvtu(int m, T z, T x);
    extern T MP_add (T z, T x, T y);
    extern T MP_sub (T z, T x, T y);
    extern T MP_mul (T z, T x, T y);
    extern T MP_div (T z, T x, T y);
    extern T MP_mod (T z, T x, T y);
    extern T MP_neg (T z, T x);
    extern T MP_addu(T z, T x, T y);
    extern T MP_subu(T z, T x, T y);
    extern T MP_mulu(T z, T x, T y);
    extern T MP_divu(T z, T x, T y);
    extern T MP_modu(T z, T x, T y);
    extern T MP_mul2u(T z, T x, T y);
    extern T MP_mul2 (T z, T x, T y);
    extern T MP_addi (T z, T x, long y);
    extern T MP_subi (T z, T x, long y);
    extern T MP_muli (T z, T x, long y);
    extern T MP_divi (T z, T x, long y);
    extern T MP_addui(T z, T x, unsigned long y);
    extern T MP_subui(T z, T x, unsigned long y);
    extern T MP_mului(T z, T x, unsigned long y);
    extern T MP_divui(T z, T x, unsigned long y);
    extern          long MP_modi (T x,          long y);
    extern unsigned long MP_modui(T x, unsigned long y);
    extern int MP_cmp  (T x, T y);
    extern int MP_cmpi (T x, long y);
    extern int MP_cmpu (T x, T y);
    extern int MP_cmpui(T x, unsigned long y);
    extern T MP_and (T z, T x, T y);
    extern T MP_or  (T z, T x, T y);
    extern T MP_xor (T z, T x, T y);
    extern T MP_not (T z, T x);
    extern T MP_andi(T z, T x, unsigned long y);
    extern T MP_ori (T z, T x, unsigned long y);
    extern T MP_xori(T z, T x, unsigned long y);
    extern T MP_lshift(T z, T x, int s);
    extern T MP_rshift(T z, T x, int s);
    extern T MP_ashift(T z, T x, int s);
    extern T     MP_fromstr(T z, const char *str,
        int basechar **end);
    extern char *MP_tostr  (char *str, int size,
        int base, T x);
    extern void  MP_fmt    (int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision);
    extern void  MP_fmtu   (int code, va_list *app,
        int put(int c, void *cl), void *cl,
        unsigned char flags[], int width, int precision);
    #undef T
    #endif

    mpcalc.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/mp.doc,v 1.11 1996/06/26 23:02:01 drh Exp $";
    #include <ctype.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <limits.h>
    #include "mem.h"
    #include "seq.h"
    #include "fmt.h"
    #include "mp.h"
    Seq_T sp;
    int ibase = 10;
    int obase = 10;
    struct {
        char *fmt;
        MP_T (*add)(MP_T, MP_T, MP_T);
        MP_T (*sub)(MP_T, MP_T, MP_T);
        MP_T (*mul)(MP_T, MP_T, MP_T);
        MP_T (*div)(MP_T, MP_T, MP_T);
        MP_T (*mod)(MP_T, MP_T, MP_T);
    } s = { "%D\n",
        MP_add,  MP_sub,  MP_mul,  MP_div,  MP_mod  },
      u = { "%U\n",
        MP_addu, MP_subu, MP_mulu, MP_divu, MP_modu },
     *f = &s;
    MP_T pop(void) {
        if (Seq_length(sp) > 0)
            return Seq_remhi(sp);
        else {
            Fmt_fprint(stderr, "?stack underflow\n");
            return MP_new(0);
        }
    }
    int main(int argc, char *argv[]) {
        int c;
        sp = Seq_new(0);
        Fmt_register('D', MP_fmt);
        Fmt_register('U', MP_fmtu);
        while ((c = getchar()) != EOF) {
            MP_T x = NULL, y = NULL, z = NULL;
            TRY
                 switch (c) {
                default:
                    if (isprint(c))
                        Fmt_fprint(stderr, "?'%c'", c);
                    else
                        Fmt_fprint(stderr, "?'\\%03o'", c);
                    Fmt_fprint(stderr, " is unimplemented\n");
                    break;
                case ' 'case '\t'case '\n'case '\f'case '\r':
                    break;
                case 'c'while (Seq_length(sp) > 0) {
                          MP_T x = Seq_remhi(sp);
                          FREE(x);
                      } break;
                case 'q'while (Seq_length(sp) > 0) {
                          MP_T x = Seq_remhi(sp);
                          FREE(x);
                      }
                      Seq_free(&sp);
                      return EXIT_SUCCESS;
                case '0'case '1'case '2'case '3'case '4':
                case '5'case '6'case '7'case '8'case '9': {
                    char buf[512];
                    z = MP_new(0);
                    {
                        int i = 0;
                        for ( ;  strchr(&"zyxwvutsrqponmlkjihgfedcba9876543210"[36-ibase],
                                tolower(c)); c = getchar(), i++)
                            if (i < (int)sizeof (buf) - 1)
                                buf[i] = c;
                        if (i > (int)sizeof (buf) - 1) {
                            i = (int)sizeof (buf) - 1;
                            Fmt_fprint(stderr,
                                "?integer constant exceeds %d digits\n", i);
                        }
                        buf[i] = '\0';
                        if (c != EOF)
                            ungetc(c, stdin);
                    }
                    MP_fromstr(z, buf, ibase, NULL);
                    break;
                }
                case '+': y = pop(); x = pop();
                      z = MP_new(0); (*f->add)(z, x, y); break;
                case '-': y = pop(); x = pop();
                      z = MP_new(0); (*f->sub)(z, x, y); break;
                case '*': y = pop(); x = pop();
                      z = MP_new(0); (*f->mul)(z, x, y); break;
                case '/': y = pop(); x = pop();
                      z = MP_new(0); (*f->div)(z, x, y); break;
                case '%': y = pop(); x = pop();
                      z = MP_new(0); (*f->mod)(z, x, y); break;
                case '&': y = pop(); x = pop();
                      z = MP_new(0);    MP_and(z, x, y); break;
                case '|': y = pop(); x = pop();
                      z = MP_new(0);    MP_or (z, x, y); break;
                case '^': y = pop(); x = pop();
                      z = MP_new(0);    MP_xor(z, x, y); break;
                case '!': z = pop(); MP_not(z, z); break;
                case '~': z = pop(); MP_neg(z, z); break;
                case 'i'case 'o': {
                    long n;
                    x = pop();
                    n = MP_toint(x);
                    if (n < 2 || n > 36)
                        Fmt_fprint(stderr, "?%d is an illegal base\n",n);
                    else if (c == 'i')
                        ibase = n;
                    else
                        obase = n;
                    if (obase == 2 || obase == 8 || obase == 16)
                        f = &u;
                    else
                        f = &s;
                    break;
                    }
                case 'p':
                    Fmt_print(f->fmt, z = pop(), obase);
                    break;
                case 'f': {
                    int n = Seq_length(sp);
                    while (--n > 0)
                        Fmt_print(f->fmt, Seq_get(sp, n), obase);
                    break;
                }
                case '<': { long s;
                        y = pop();
                        z = pop();
                        s = MP_toint(y);
                        if (s < 0 || s > INT_MAX) {
                            Fmt_fprint(stderr,
                                "?%d is an illegal shift amount\n", s);
                            break;
                        }; MP_lshift(z, z, s); break; }
                case '>': { long s;
                        y = pop();
                        z = pop();
                        s = MP_toint(y);
                        if (s < 0 || s > INT_MAX) {
                            Fmt_fprint(stderr,
                                "?%d is an illegal shift amount\n", s);
                            break;
                        }; MP_rshift(z, z, s); break; }
                case 'k': {
                    long n;
                    x = pop();
                    n = MP_toint(x);
                    if (n < 2 || n > INT_MAX)
                        Fmt_fprint(stderr,
                            "?%d is an illegal precision\n", n);
                    else if (Seq_length(sp) > 0)
                        Fmt_fprint(stderr, "?nonempty stack\n");
                    else
                        MP_set(n);
                    break;
                    }
                case 'd': {
                    MP_T x = pop();
                    z = MP_new(0);
                    Seq_addhi(sp, x);
                    MP_addui(z, x, 0);
                    break;
                    }
                }
            EXCEPT(MP_Overflow)
                Fmt_fprint(stderr, "?overflow\n");
            EXCEPT(MP_Dividebyzero)
                Fmt_fprint(stderr, "?divide by 0\n");
            END_TRY;
            if (z)
                Seq_addhi(sp, z);
            FREE(x);
            FREE(y);
        }
        while (Seq_length(sp) > 0) {
            MP_T x = Seq_remhi(sp);
            FREE(x);
        }
        Seq_free(&sp);
        return EXIT_SUCCESS;
    }

    thread.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $ */
    #ifndef THREAD_INCLUDED
    #define THREAD_INCLUDED
    #include "except.h"
    #define T Thread_T
    typedef struct T *T;
    extern const Except_T Thread_Failed;
    extern const Except_T Thread_Alerted;
    extern int  Thread_init (int preempt, ...);
    extern T    Thread_new  (int apply(void *),
                    void *args, int nbytes, ...);
    extern void Thread_exit (int code);
    extern void Thread_alert(T t);
    extern T    Thread_self (void);
    extern int  Thread_join (T t);
    extern void Thread_pause(void);
    #undef T
    #endif

     

    sem.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $ */
    #ifndef SEM_INCLUDED
    #define SEM_INCLUDED
    #define T Sem_T
    typedef struct T {
        int count;
        void *queue;
    } T;
    #define LOCK(mutex) do { Sem_T *_yymutex = &(mutex); \
        Sem_wait(_yymutex);
    #define END_LOCK Sem_signal(_yymutex); } while (0)
    extern void Sem_init  (T *s, int count);
    extern T   *Sem_new   (int count);
    extern void Sem_wait  (T *s);
    extern void Sem_signal(T *s);
    #undef T
    #endif

     

    thread.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include </usr/include/signal.h>
    #include <sys/time.h>
    #include "assert.h"
    #include "mem.h"
    #include "thread.h"
    #include "sem.h"
    void _MONITOR(void) {}
    extern void _ENDMONITOR(void);
    #define T Thread_T
    #define isempty(q) ((q) == NULL)
    struct T {
        unsigned long *sp;                        /* must be first */
        T link;
        T *inqueue;
        T handle;
        Except_Frame *estack;
        int code;
        T join;
        T next;
        int alerted;
    };
    static T ready = NULL;
    static T current;
    static int nthreads;
    static struct Thread_T root;
    static T join0;
    static T freelist;
    const Except_T Thread_Alerted = { "Thread alerted" };
    const Except_T Thread_Failed =
        { "Thread creation failed" };
    static int critical;
    extern void _swtch(T from, T to);
    static void put(T t, T *q) {
        assert(t);
        assert(t->inqueue == NULL && t->link == NULL);
        if (*q) {
            t->link = (*q)->link;
            (*q)->link = t;
        } else
            t->link = t;
        *q = t;
        t->inqueue = q;
    }
    static T get(T *q) {
        T t;
        assert(!isempty(*q));
        t = (*q)->link;
        if (t == *q)
            *q = NULL;
        else
            (*q)->link = t->link;
        assert(t->inqueue == q);
        t->link = NULL;
        t->inqueue = NULL;
        return t;
    }
    static void delete(T t, T *q) {
        T p;
        assert(t->link && t->inqueue == q);
        assert(!isempty(*q));
        for (p = *q; p->link != t; p = p->link)
            ;
        if (p == t)
            *q = NULL;
        else {
            p->link = t->link;
            if (*q == t)
                *q = p;
        }
        t->link = NULL;
        t->inqueue = NULL;
    }
    static void run(void) {
        T t = current;
        current = get(&ready);
        t->estack = Except_stack;
        Except_stack = current->estack;
        _swtch(t, current);
    }
    static void testalert(void) {
        if (current->alerted) {
            current->alerted = 0;
            RAISE(Thread_Alerted);
        }
    }
    static void release(void) {
        T t;
        do { critical++;
        while ((t = freelist) != NULL) {
            freelist = t->next;
            FREE(t);
        }
        critical--; } while (0);
    }
    #if linux
    #include <asm/sigcontext.h>
    static int interrupt(int sig, struct sigcontext_struct sc) {
        if (critical ||
           sc.eip >= (unsigned long)_MONITOR
        && sc.eip <= (unsigned long)_ENDMONITOR)
            return 0;
        put(current, &ready);
        do { critical++;
        sigsetmask(sc.oldmask);
        critical--; } while (0);
        run();
        return 0;
    }
    #else
    static int interrupt(int sig, int code,
        struct sigcontext *scp) {
        if (critical ||
           scp->sc_pc >= (unsigned long)_MONITOR
        && scp->sc_pc <= (unsigned long)_ENDMONITOR)
            return 0;
        put(current, &ready);
        sigsetmask(scp->sc_mask);
        run();
        return 0;
    }
    #endif
    int Thread_init(int preempt, ...) {
        assert(preempt == 0 || preempt == 1);
        assert(current == NULL);
        root.handle = &root;
        current = &root;
        nthreads = 1;
        if (preempt) {
            {
                struct sigaction sa;
                memset(&sa, '\0'sizeof sa);
                sa.sa_handler = (void (*)())interrupt;
                if (sigaction(SIGVTALRM, &sa, NULL) < 0)
                    return 0;
            }
            {
                struct itimerval it;
                it.it_value.tv_sec     =  0;
                it.it_value.tv_usec    = 50;
                it.it_interval.tv_sec  =  0;
                it.it_interval.tv_usec = 50;
                if (setitimer(ITIMER_VIRTUAL, &it, NULL) < 0)
                    return 0;
            }
        }
        return 1;
    }
    T Thread_self(void) {
        assert(current);
        return current;
    }
    void Thread_pause(void) {
        assert(current);
        put(current, &ready);
        run();
    }
    int Thread_join(T t) {
        assert(current && t != current);
        testalert();
        if (t) {
            if (t->handle == t) {
                put(current, &t->join);
                run();
                testalert();
                return current->code;
            } else
                return -1;
        } else {
            assert(isempty(join0));
            if (nthreads > 1) {
                put(current, &join0);
                run();
                testalert();
            }
            return 0;
        }
    }
    void Thread_exit(int code) {
        assert(current);
        release();
        if (current != &root) {
            current->next = freelist;
            freelist = current;
        }
        current->handle = NULL;
        while (!isempty(current->join)) {
            T t = get(&current->join);
            t->code = code;
            put(t, &ready);
        }
        if (!isempty(join0) && nthreads == 2) {
            assert(isempty(ready));
            put(get(&join0), &ready);
        }
        if (--nthreads == 0)
            exit(code);
        else
            run();
    }
    void Thread_alert(T t) {
        assert(current);
        assert(t && t->handle == t);
        t->alerted = 1;
        if (t->inqueue) {
            delete(t, t->inqueue);
            put(t, &ready);
        }
    }
    T Thread_new(int apply(void *), void *args,
        int nbytes, ...) {
         T t;
        assert(current);
        assert(apply);
        assert(args && nbytes >= 0 || args == NULL);
        if (args == NULL)
            nbytes = 0;
        {
            int stacksize = (16*1024+sizeof (*t)+nbytes+15)&~15;
            release();
            do { critical++;
            TRY
                t = ALLOC(stacksize);
                memset(t, '\0'sizeof *t);
            EXCEPT(Mem_Failed)
                t = NULL;
            END_TRY;
            critical--; } while (0);
            if (t == NULL)
                RAISE(Thread_Failed);
            t->sp = (void *)((char *)t + stacksize);
            while (((unsigned long)t->sp)&15)
                t->sp--;
        }
        t->handle = t;
        if (nbytes > 0) {
            t->sp -= ((nbytes + 15U)&~15)/sizeof (*t->sp);
            do { critical++;
            memcpy(t->sp, args, nbytes);
            critical--; } while (0);
            args = t->sp;
        }
    #if alpha
        { extern void _start(void);
          t->sp -= 112/8;
          t->sp[(48+24)/8] = (unsigned long)Thread_exit;
          t->sp[(48+16)/8] = (unsigned long)args;
          t->sp[(488)/8] = (unsigned long)apply;
          t->sp[(480)/8] = (unsigned long)_start; }
    #elif mips
        { extern void _start(void);
          t->sp -= 16/4;
          t->sp -= 88/4;
          t->sp[(48+20)/4] = (unsigned long)Thread_exit;
          t->sp[(48+28)/4] = (unsigned long)args;
          t->sp[(48+32)/4] = (unsigned long)apply;
          t->sp[(48+36)/4] = (unsigned long)_start; }
    #elif sparc
        {     int i; void *fp; extern void _start(void);
              for (i = 0; i < 8; i++)
                  *--t->sp = 0;
              *--t->sp = (unsigned long)args;
              *--t->sp = (unsigned long)apply;
              t->sp -= 64/4;
              fp = t->sp;
              *--t->sp = (unsigned long)_start - 8;
              *--t->sp = (unsigned long)fp;
              t->sp -= 64/4; }
    #elif linux && i386
        { extern void _thrstart(void);
          t->sp -= 4/4;
          *t->sp = (unsigned long)_thrstart;
          t->sp -= 16/4;
          t->sp[4/4]  = (unsigned long)apply;
          t->sp[8/4]  = (unsigned long)args;
          t->sp[12/4] = (unsigned long)t->sp + (4+16)/4; }
    #else
        Unsupported platform
    #endif
        nthreads++;
        put(t, &ready);
        return t;
    }
    #undef T
    #define T Sem_T
    T *Sem_new(int count) {
        T *s;
        NEW(s);
        Sem_init(s, count);
        return s;
    }
    void Sem_init(T *s, int count) {
        assert(current);
        assert(s);
        s->count = count;
        s->queue = NULL;
    }
    void Sem_wait(T *s) {
        assert(current);
        assert(s);
        testalert();
        if (s->count <= 0) {
            put(current, (Thread_T *)&s->queue);
            run();
            testalert();
        } else
            --s->count;
    }
    void Sem_signal(T *s) {
        assert(current);
        assert(s);
        if (s->count == 0 && !isempty(s->queue)) {
            Thread_T t = get((Thread_T *)&s->queue);
            assert(!t->alerted);
            put(t, &ready);
        } else
            ++s->count;
    }
    #undef T

     

    thread-nt.c

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <limits.h>
    #include <windows.h>
    #include <process.h>
    #include "assert.h"
    #include "mem.h"
    #include "thread.h"
    #include "sem.h"

    static char rcsid[] = "$Id: thread-nt.c,v 1.5 1997/07/29 17:10:25 drh Exp $";

    #define T Thread_T
    struct T {
        DWORD IDThread;        /* Win 32 thread identifier */
        T handle;        /* self pointer */
        int code;        /* exit code */
        HANDLE join;        /* join semaphore */
        T joinlist;        /* threads waiting on join */
        T link;            /* next thread on this join list */
        T next;            /* next thread on this hash chain */
        int alerted;        /* 1 if this thread has been alerted */
        int (*apply)(void *);    /* initial function for this thread */
        void *args;        /* argument for apply */
    };

    const Except_T Thread_Alerted = { "Thread alerted" };
    const Except_T Thread_Failed  = { "Thread creation failed" };

    static T allthreads[317];
    #define HASH(id) ((int)((id)%(sizeof allthreads/sizeof allthreads[0])))
    static int nthreads;        /* number of threads in allthreads */
    static T root;
    static HANDLE join0;        /* Thread_join(NULL) semaphore */
    static int join0count;        /* number of threads waiting on join0; always 0 or 1 */

    static int critical;
    static CRITICAL_SECTION csection;
    #define ENTERCRITICAL EnterCriticalSection(&csection); assert(critical == 0); critical++
    #define LEAVECRITICAL   critical--; assert(critical == 0); LeaveCriticalSection(&csection)

    static T getThreadByID(DWORD id) {
        T t;

        ENTERCRITICAL;
        for (t = allthreads[HASH(id)]; t != NULL; t = t->next)
            if (t->IDThread == id)
                break;
        LEAVECRITICAL;
        assert(t);
        return t;
    }

    static void removeThread(T t) {
        T *q;

        ENTERCRITICAL;
        q = &allthreads[HASH(t->IDThread)];
        for ( ; *q != NULL && *q != t; q = &(*q)->next)
            ;
        assert(*q == t);
        *q = t->next;
        nthreads--;
        t->handle = NULL;
        LEAVECRITICAL;
    }

    static void addThread(T t) {
        T *q;

        ENTERCRITICAL;
        q = &allthreads[HASH(t->IDThread)];
        t->next = *q;
        *q = t;
        nthreads++;
        t->handle = t;
        LEAVECRITICAL;
    }

    static void testalert(T t) {
        ENTERCRITICAL;
        if (t->alerted) {
            t->alerted = 0;
            LEAVECRITICAL;
            RAISE(Thread_Alerted);
        }
        LEAVECRITICAL;
    }

    int Thread_init(int preempt, ...) {
        assert(preempt == 0 || preempt == 1);
        assert(root == NULL);
        TRY
            NEW0(root);
        EXCEPT(Mem_Failed)
            return -1;
        END_TRY;
        join0 = CreateSemaphore(NULL, 01, NULL);
        if (join0 == NULL)
            return -1;
        root->join = CreateSemaphore(NULL, 0, INT_MAX, NULL);
        if (root->join == NULL) {
            BOOL result = CloseHandle(join0);
            assert(result == TRUE);
            return -1;
        }
        InitializeCriticalSection(&csection);
        root->IDThread = GetCurrentThreadId();
        addThread(root);
        /* handle preempt == 0 */
        return 1;
    }

    T Thread_self(void) {
        assert(root);
        return getThreadByID(GetCurrentThreadId());
    }

    void Thread_pause(void) {
        assert(root);
        Sleep(0);
    }

    int Thread_join(T t) {
        T current = Thread_self();

        assert(root);
        assert(t != current);
        testalert(current);
        if (t != NULL) {
            ENTERCRITICAL;
            if (t->handle == t) {
                HANDLE join = t->join;
                DWORD result;
                assert(current->link == NULL);
                current->link = t->joinlist;
                t->joinlist = current;
                LEAVECRITICAL;
                result = WaitForSingleObject(join, INFINITE);
                assert(result != WAIT_FAILED);
                testalert(current);
                return current->code;
            } else {
                LEAVECRITICAL;
                return -1;
            }
        }
        ENTERCRITICAL;
        if (nthreads > 1) {
            DWORD result;
            assert(join0count == 0);
            join0count++;
            LEAVECRITICAL;
            result = WaitForSingleObject(join0, INFINITE);
            assert(result != WAIT_FAILED);
            ENTERCRITICAL;
            join0count--;
            LEAVECRITICAL;
            testalert(current);
        } else {
            assert(join0count == 0);
            LEAVECRITICAL;
            return 0;
        }
    }

    void Thread_exit(int code) {
        BOOL result;
        T current = Thread_self();

        removeThread(current);
        ENTERCRITICAL;
        if (current->joinlist != NULL) {
            T t, n;
            int count = 0;
            assert(current->join);
            for (t = current->joinlist; t != NULL; t = n) {
                t->code = code;
                n = t->link;
                t->link = NULL;
                count++;
            }
            current->joinlist = NULL;
            result = ReleaseSemaphore(current->join, count, NULL);
            assert(result == TRUE);
        }
        result = CloseHandle(current->join);
        assert(result == TRUE);
        current->join = NULL;
        if (join0count > 0 && nthreads == 1) {
            assert(join0count == 1);
            result = ReleaseSemaphore(join0, 1, NULL);
            assert(result == TRUE);
        }
        if (nthreads == 0) {
            result = CloseHandle(join0);
            assert(result == TRUE);
        }
        FREE(current);
        LEAVECRITICAL;
        _endthreadex(code);
    }

    void Thread_alert(T t) {
        assert(root);
        ENTERCRITICAL;
        assert(t && t->handle == t);
        t->alerted = 1;
        LEAVECRITICAL;
    }

    static unsigned __stdcall start(void *p) {
        T t = p;

        Except_stack = NULL;
        Thread_exit((*t->apply)(t->args));
        return 0;
    }

    T Thread_new(int apply(void *), void *args, int nbytes, ...) {
        T t;
        HANDLE hThread;

        assert(root);
        assert(apply);
        assert(args && nbytes >= 0 || args == NULL);
        if (args == NULL)
            nbytes = 0;
        TRY
            t = ALLOC((sizeof (*t) + nbytes + 15)&~15);
            memset(t, '\0'sizeof *t);
        EXCEPT(Mem_Failed)
            RAISE(Thread_Failed);
        END_TRY;
        t->join = CreateSemaphore(NULL, 0, INT_MAX, NULL);
        if (t->join == NULL) {
            FREE(t);
            RAISE(Thread_Failed);
        }
        if (nbytes > 0) {
            t->args = t + 1;
            memcpy(t->args, args, nbytes);
        } else
            t->args = args;
        t->apply = apply;
        hThread = (HANDLE)_beginthreadex(
            NULL,        /* default security attributes */
            0,        /* default stack size */
            start,        /* initial function */
            t,        /* start's argument */
            0,        /* default thread creation flags */
            &t->IDThread    /* where to store the thread id */
            );
        if (hThread == NULL) {
            CloseHandle(t->join);
            FREE(t);
            RAISE(Thread_Failed);
        }
        CloseHandle(hThread);
        addThread(t);
        return t;
    }
    #undef T

    #define T Sem_T
    T *Sem_new(int count) {
        T *s;

        NEW(s);
        Sem_init(s, count);
        return s;
    }

    void Sem_init(T *s, int count) {
        assert(root);
        assert(s);
        assert(count >= 0);
        s->count = 0;
        s->queue = CreateSemaphore(NULL, count, INT_MAX, NULL);
        assert(s->queue);
    }

    void Sem_wait(T *s) {
        DWORD result;
        Thread_T current = Thread_self();

        assert(s);
        testalert(current);
        result = WaitForSingleObject(s->queue, INFINITE);
        assert(result != WAIT_FAILED);
        ENTERCRITICAL;
        if (current->alerted) {
            BOOL result;
            current->alerted = 0;
            LEAVECRITICAL;
            result = ReleaseSemaphore(s->queue, 1, NULL);
            assert(result == TRUE);
            RAISE(Thread_Alerted);
        }
        LEAVECRITICAL;
    }

    void Sem_signal(T *s) {
        BOOL result;

        assert(root);
        assert(s);
        result = ReleaseSemaphore(s->queue, 1, NULL);
        assert(result == TRUE);
    }
    #undef T

     

     

    chan.h

    View Code
    /* $Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $ */
    #ifndef CHAN_INCLUDED
    #define CHAN_INCLUDED
    #define T Chan_T
    typedef struct T *T;
    extern T   Chan_new    (void);
    extern int Chan_send   (T c, const void *ptr, int size);
    extern int Chan_receive(T c,       void *ptr, int size);
    #undef T
    #endif

     

    chain.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
    #include <string.h>
    #include "assert.h"
    #include "mem.h"
    #include "chan.h"
    #include "sem.h"
    #define T Chan_T
    struct T {
        const void *ptr;
        int *size;
        Sem_T send, recv, sync;
    };
    T Chan_new(void) {
        T c;
        NEW(c);
        Sem_init(&c->send, 1);
        Sem_init(&c->recv, 0);
        Sem_init(&c->sync, 0);
        return c;
    }
    int Chan_send(Chan_T c, const void *ptr, int size) {
        assert(c);
        assert(ptr);
        assert(size >= 0);
        Sem_wait(&c->send);
        c->ptr = ptr;
        c->size = &size;
        Sem_signal(&c->recv);
        Sem_wait(&c->sync);
        return size;
    }
    int Chan_receive(Chan_T c, void *ptr, int size) {
        int n;
        assert(c);
        assert(ptr);
        assert(size >= 0);
        Sem_wait(&c->recv);
        n = *c->size;
        if (size < n)
            n = size;
        *c->size = n;
        if (n > 0)
            memcpy(ptr, c->ptr, n);
        Sem_signal(&c->sync);
        Sem_signal(&c->send);
        return n;
    }

    sort.c

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include "assert.h"
    #include "fmt.h"
    #include "thread.h"
    #include "mem.h"
    struct args {
        int *a;
        int lb, ub;
    };
    int cutoff = 10000;
    int partition(int a[], int i, int j) {
        int v, k, t;
        j++;
        k = i;
        v = a[k];
        while (i < j) {
            i++; while (a[i] < v && i < j) i++;
            j--; while (a[j] > v         ) j--;
            if (i < j) { t = a[i]; a[i] = a[j]; a[j] = t; }
        }
        t = a[k]; a[k] = a[j]; a[j] = t;
        return j;
    }
    int quick(void *cl) {
        struct args *p = cl;
        int lb = p->lb, ub = p->ub;
        if (lb < ub) {
            int k = partition(p->a, lb, ub);
            p->lb = lb;
            p->ub = k - 1;
            if (k - lb > cutoff) {
                Thread_T t;
                t = Thread_new(quick, p, sizeof *p, NULL);
                Fmt_print("thread %p sorted %d..%d\n", t, lb, k - 1);
            } else
                quick(p);
            p->lb = k + 1;
            p->ub = ub;
            if (ub - k > cutoff) {
                Thread_T t;
                t = Thread_new(quick, p, sizeof *p, NULL);
                Fmt_print("thread %p sorted %d..%d\n", t, k + 1, ub);
            } else
                quick(p);
        }
        return EXIT_SUCCESS;
    }
    void sort(int *x, int n, int argc, char *argv[]) {
        struct args args;
        if (argc >= 3)
            cutoff = atoi(argv[2]);
        args.a = x;
        args.lb = 0;
        args.ub = n - 1;
        quick(&args);
        Thread_join(NULL);
    }
    main(int argc, char *argv[]) {
        int i, n = 100000, *x, preempt;
        preempt = Thread_init(1, NULL);
        assert(preempt == 1);
        if (argc >= 2)
            n = atoi(argv[1]);
        x = CALLOC(n, sizeof (int));
        srand(time(NULL));
        for (i = 0; i < n; i++)
            x[i] = rand();
        sort(x, n, argc, argv);
        for (i = 1; i < n; i++)
            if (x[i] < x[i-1])
                break;
        assert(i == n);
        Thread_exit(EXIT_SUCCESS);
        return EXIT_SUCCESS;
    }

     

     

     

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
    #include <stdio.h>
    #include <stdlib.h>
    #include "assert.h"
    #include "fmt.h"
    #include "thread.h"
    #include "sem.h"
    #define NBUMP 30000
    struct args {
        Sem_T *mutex;
        int *ip;
    };
    int unsafe(void *cl) {
        int i, *ip = cl;
        for (i = 0; i < NBUMP; i++)
            *ip = *ip + 1;
        return EXIT_SUCCESS;
    }
    int safe(void *cl) {
        struct args *p = cl;
        int i;
        for (i = 0; i < NBUMP; i++)
            LOCK(*p->mutex)
                *p->ip = *p->ip + 1;
            END_LOCK;
        return EXIT_SUCCESS;
    }
    int n;
    int main(int argc, char *argv[]) {
        int m = 5, preempt;
        preempt = Thread_init(1, NULL);
        assert(preempt == 1);
        if (argc >= 2)
            m = atoi(argv[1]);
        n = 0;
        {
            int i;
            for (i = 0; i < m; i++)
                Thread_new(unsafe, &n, 0, NULL);
            Thread_join(NULL);
        }
        Fmt_print("%d == %d\n", n, NBUMP*m);
        n = 0;
        {
            int i;
            struct args args;
            Sem_T mutex;
            Sem_init(&mutex, 1);
            args.mutex = &mutex;
            args.ip = &n;
            for (i = 0; i < m; i++)
                Thread_new(safe, &args, sizeof args, NULL);
            Thread_join(NULL);
        }
        Fmt_print("%d == %d\n", n, NBUMP*m);
        Thread_exit(EXIT_SUCCESS);
        return EXIT_SUCCESS;
    }

     

     

    View Code
    static char rcsid[] = "$Id: H:/drh/idioms/book/RCS/thread.doc,v 1.11 1997/02/21 19:50:51 drh Exp $";
    #include <stdio.h>
    #include <stdlib.h>
    #include "assert.h"
    #include "fmt.h"
    #include "thread.h"
    #include "chan.h"
    struct args {
        Chan_T c;
        int n, last;
    };
    int source(void *cl) {
        struct args *p = cl;
        int i = 2;
        if (Chan_send(p->c, &i, sizeof i))
            for (i = 3; Chan_send(p->c, &i, sizeof i); )
                i += 2;
        return EXIT_SUCCESS;
    }
    void filter(int primes[], Chan_T input, Chan_T output) {
        int j, x;
        for (;;) {
            Chan_receive(input, &x, sizeof x);
            for (j = 0; primes[j] != 0 && x%primes[j] != 0; j++)
                ;
            if (primes[j] == 0)
                 if (Chan_send(output, &x, sizeof x) == 0)
                    break;
        }
        Chan_receive(input, &x, 0);
    }
    int sink(void *cl) {
        struct args *p = cl;
        Chan_T input = p->c;
        int i = 0, j, x, primes[256];
        primes[0] = 0;
        for (;;) {
            Chan_receive(input, &x, sizeof x);
             for (j = 0; primes[j] != 0 && x%primes[j] != 0; j++)
                ;
            if (primes[j] == 0) {
                if (x > p->last)
                    break;
                Fmt_print(" %d", x);
                primes[i++] = x;
                primes[i] = 0;
                if (i == p->n)
                    {
                        p->c = Chan_new();
                        Thread_new(sink, p, sizeof *p, NULL);
                        filter(primes, input, p->c);
                        return EXIT_SUCCESS;
                    }
            }
        }
        Fmt_print("\n");
        Chan_receive(input, &x, 0);
         return EXIT_SUCCESS;
    }
    int main(int argc, char *argv[]) {
        struct args args;
        Thread_init(1, NULL);
        args.c = Chan_new();
        Thread_new(source, &args, sizeof args, NULL);
        args.n    = argc > 2 ? atoi(argv[2]) : 5;
        args.last = argc > 1 ? atoi(argv[1]) : 1000;
        Thread_new(sink,   &args, sizeof args, NULL);
        Thread_exit(EXIT_SUCCESS);
        return EXIT_SUCCESS;
    }
  • 相关阅读:
    数据挖掘实践(9):基础理论(九)数学基础(九)概率(五)⻉叶斯公式
    数据挖掘实践(8):基础理论(八)数学基础(八)概率(四)参数估计(二)
    数据挖掘实践(7):基础理论(七)数学基础(七)概率(三)参数估计(一)
    数据挖掘实践(6):基础理论(六)数学基础(六)概率(二)随机变量
    Linux上快速入门英特尔Optane DC Persistent Memory Module的配置与使用
    ovs 流表
    Cannot get thread event message: debugger service failed
    gdb ovs
    rror while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory
    glibc
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2624444.html
Copyright © 2011-2022 走看看