C语言接口与实现[+]

来源:互联网 发布:python远程监控服务器 编辑:程序博客网 时间:2024/05/16 18:29

第1章 简介

1. literate程序

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

第2章 接口与实现

1. 接口与实现的关系

2. Arith接口及实现:

arith.h:

复制代码
/* $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

 

复制代码
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

stack.c 

复制代码
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

atom.c:

复制代码
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 

复制代码
/* $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 

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

 

arena.c

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
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

复制代码
/* $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

复制代码
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

复制代码
/* $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

复制代码
/* $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

复制代码
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

复制代码
#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

复制代码
/* $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

复制代码
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

复制代码
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;
}
复制代码

 

 

 

 

复制代码
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;
}
复制代码

 

 

复制代码
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;
}
复制代码
分类: C/C++笔记
0 0
原创粉丝点击