sxpr.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,231 行 · 第 1/2 页

C
1,231
字号
/* * Copyright (C) 2001 - 2004 Mike Wray <mike.wray@hp.com> * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or  (at your option) any later version. This library is  * distributed in the  hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */#include <stdarg.h>#include "sys_string.h"#include "lexis.h"#include "sys_net.h"#include "hash_table.h"#include "sxpr.h"#ifdef __KERNEL__#include <linux/errno.h>#else#include <errno.h>#endif#ifdef __KERNEL__#include <linux/random.h>int rand(void){    int v;    get_random_bytes(&v, sizeof(v));    return v;}#else#include <stdlib.h>#endif#undef free/** @file * General representation of sxprs. * Includes print, equal, and free functions for the sxpr types. * * Zero memory containing an Sxpr will have the value ONONE - this is intentional. * When a function returning an sxpr cannot allocate memory we return ONOMEM. * */static int atom_print(IOStream *io, Sxpr obj, unsigned flags);static int atom_equal(Sxpr x, Sxpr y);static void atom_free(Sxpr obj);static Sxpr atom_copy(Sxpr obj);static int string_print(IOStream *io, Sxpr obj, unsigned flags);static int string_equal(Sxpr x, Sxpr y);static void string_free(Sxpr obj);static Sxpr string_copy(Sxpr obj);static int cons_print(IOStream *io, Sxpr obj, unsigned flags);static int cons_equal(Sxpr x, Sxpr y);static void cons_free(Sxpr obj);static Sxpr cons_copy(Sxpr obj);static int null_print(IOStream *io, Sxpr obj, unsigned flags);static int none_print(IOStream *io, Sxpr obj, unsigned flags);static int int_print(IOStream *io, Sxpr obj, unsigned flags);static int bool_print(IOStream *io, Sxpr obj, unsigned flags);static int err_print(IOStream *io, Sxpr obj, unsigned flags);static int nomem_print(IOStream *io, Sxpr obj, unsigned flags);/** Type definitions. */static SxprType types[1024] = {    [T_NONE]     { .type=    T_NONE,     .name= "none",       .print= none_print      },    [T_NULL]     { .type=    T_NULL,     .name= "null",       .print= null_print      },    [T_UINT]     { .type=    T_UINT,     .name= "int",        .print= int_print,      },    [T_BOOL]     { .type=    T_BOOL,     .name= "bool",       .print= bool_print,     },    [T_ERR]      { .type=    T_ERR,      .name= "err",        .print= err_print,      },    [T_NOMEM]    { .type=    T_ERR,      .name= "nomem",      .print= nomem_print,    },    [T_ATOM]     { .type=    T_ATOM,     .name= "atom",       .print= atom_print,                   .pointer= TRUE,                   .free=    atom_free,                   .equal=   atom_equal,                   .copy=    atom_copy,                 },    [T_STRING]   { .type=    T_STRING,   .name= "string",     .print= string_print,                   .pointer= TRUE,                   .free=    string_free,                   .equal=   string_equal,                   .copy=    string_copy,                 },    [T_CONS]     { .type=    T_CONS,     .name= "cons",       .print= cons_print,                   .pointer= TRUE,                   .free=    cons_free,                   .equal=   cons_equal,                   .copy=    cons_copy,                 },};/** Number of entries in the types array. */static int type_sup = sizeof(types)/sizeof(types[0]);/** Define a type. * The tydef must have a non-zero type code. * It is an error if the type code is out of range or already defined. * * @param tydef type definition * @return 0 on success, error code otherwise */int def_sxpr_type(SxprType *tydef){    int err = 0;    int ty = tydef->type;    if(ty < 0 || ty >= type_sup){        err = -EINVAL;        goto exit;    }    if(types[ty].type){        err = -EEXIST;        goto exit;    }    types[ty] = *tydef;  exit:    return err;    }/** Get the type definition for a given type code. * * @param ty type code * @return type definition or null */SxprType *get_sxpr_type(int ty){    if(0 <= ty && ty < type_sup){        return types+ty;    }    return NULL;}/** The default print function. * * @param io stream to print to * @param x sxpr to print * @param flags print flags * @return number of bytes written on success */int default_print(IOStream *io, Sxpr x, unsigned flags){    return IOStream_print(io, "#<%u %lu>\n", get_type(x), get_ul(x));}/** The default equal function. * Uses eq(). * * @param x sxpr to compare * @param y sxpr to compare * @return 1 if equal, 0 otherwise */int default_equal(Sxpr x, Sxpr y){    return eq(x, y);}/** General sxpr print function. * Prints an sxpr on a stream using the print function for the sxpr type. * Printing is controlled by flags from the PrintFlags enum. * If PRINT_TYPE is in the flags the sxpr type is printed before the sxpr * (for debugging). * * @param io stream to print to * @param x sxpr to print * @param flags print flags * @return number of bytes written */int objprint(IOStream *io, Sxpr x, unsigned flags){    SxprType *def = get_sxpr_type(get_type(x));    ObjPrintFn *print_fn = (def && def->print ? def->print : default_print);    int k = 0;    if(!io) return k;    if(flags & PRINT_TYPE){        k += IOStream_print(io, "%s:", def->name);    }    if(def->pointer && (flags & PRINT_ADDR)){        k += IOStream_print(io, "<%p>", get_ptr(x));    }    k += print_fn(io, x, flags);    return k;}Sxpr objcopy(Sxpr x){    SxprType *def = get_sxpr_type(get_type(x));    ObjCopyFn *copy_fn = (def ? def->copy : NULL);    Sxpr v;    if(copy_fn){        v = copy_fn(x);    } else if(def->pointer){        v = ONOMEM;    } else {        v = x;    }    return v;}/** General sxpr free function. * Frees an sxpr using the free function for its type. * Free functions must recursively free any subsxprs. * If no function is defined then the default is to * free sxprs whose type has pointer true. * Sxprs must not be used after freeing. * * @param x sxpr to free */void objfree(Sxpr x){    SxprType *def = get_sxpr_type(get_type(x));    if(def){        if(def->free){            def->free(x);        } else if (def->pointer){            hfree(x);        }    }}/** General sxpr equality function. * Compares x and y using the equal function for x. * Uses default_equal() if x has no equal function. * * @param x sxpr to compare * @param y sxpr to compare * @return 1 if equal, 0 otherwise */int objequal(Sxpr x, Sxpr y){    SxprType *def = get_sxpr_type(get_type(x));    ObjEqualFn *equal_fn = (def && def->equal ? def->equal : default_equal);    return equal_fn(x, y);}/** Search for a key in an alist. * An alist is a list of conses, where the cars * of the conses are the keys. Compares keys using equality. * * @param k key * @param l alist to search * @return first element of l with car k, or ONULL */Sxpr assoc(Sxpr k, Sxpr l){    for( ; CONSP(l) ; l = CDR(l)){        Sxpr x = CAR(l);        if(CONSP(x) && objequal(k, CAR(x))){            return x;           }    }    return ONULL;}/** Search for a key in an alist. * An alist is a list of conses, where the cars * of the conses are the keys. Compares keys using eq. * * @param k key * @param l alist to search * @return first element of l with car k, or ONULL */Sxpr assocq(Sxpr k, Sxpr l){    for( ; CONSP(l); l = CDR(l)){        Sxpr x = CAR(l);        if(CONSP(x) && eq(k, CAR(x))){            return x;        }    }    return ONULL;}/** Add a new key and value to an alist. * * @param k key * @param l value * @param l alist * @return l with the new cell added to the front */Sxpr acons(Sxpr k, Sxpr v, Sxpr l){    Sxpr x, y;    x = cons_new(k, v);    if(NOMEMP(x)) return x;    y = cons_new(x, l);    if(NOMEMP(y)) cons_free_cells(x);    return y;}/** Test if a list contains an element. * Uses sxpr equality. * * @param l list * @param x element to look for * @return a tail of l with x as car, or ONULL */Sxpr cons_member(Sxpr l, Sxpr x){    for( ; CONSP(l) && !eq(x, CAR(l)); l = CDR(l)){}    return l;}/** Test if a list contains an element satisfying a test. * The test function is called with v and an element of the list. * * @param l list * @param test_fn test function to use * @param v value for first argument to the test * @return a tail of l with car satisfying the test, or 0 */Sxpr cons_member_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){    for( ; CONSP(l) && !test_fn(v, CAR(l)); l = CDR(l)){ }    return l;}/** Test if the elements of list 't' are a subset of the elements * of list 's'. Element order is not significant. * * @param s element list to check subset of * @param t element list to check if is a subset * @return 1 if is a subset, 0 otherwise */int cons_subset(Sxpr s, Sxpr t){    for( ; CONSP(t); t = CDR(t)){        if(!CONSP(cons_member(s, CAR(t)))){            return 0;        }    }    return 1;}/** Test if two lists have equal sets of elements. * Element order is not significant. * * @param s list to check * @param t list to check * @return 1 if equal, 0 otherwise */int cons_set_equal(Sxpr s, Sxpr t){    return cons_subset(s, t) && cons_subset(t, s);}#ifdef USE_GC/*============================================================================*//* The functions inside this ifdef are only safe if GC is used. * Otherwise they may leak memory. *//** Remove an element from a list (GC only). * Uses sxpr equality and removes all instances, even * if there are more than one. * * @param l list to remove elements from * @param x element to remove * @return modified input list */Sxpr cons_remove(Sxpr l, Sxpr x){    return cons_remove_if(l, eq, x);}/** Remove elements satisfying a test (GC only). * The test function is called with v and an element of the set. * * @param l list to remove elements from * @param test_fn function to use to decide if an element should be removed * @return modified input list */Sxpr cons_remove_if(Sxpr l, ObjEqualFn *test_fn, Sxpr v){    Sxpr prev = ONULL, elt, next;    for(elt = l; CONSP(elt); elt = next){        next = CDR(elt);        if(test_fn(v, CAR(elt))){            if(NULLP(prev)){                l = next;            } else {                CDR(prev) = next;            }        }    }    return l;}/** Set the value for a key in an alist (GC only). * If the key is present, changes the value, otherwise * adds a new cell. * * @param k key * @param v value * @param l alist * @return modified or extended list */Sxpr setf(Sxpr k, Sxpr v, Sxpr l){    Sxpr e = assoc(k, l);    if(NULLP(e)){        l = acons(k, v, l);    } else {        CAR(CDR(e)) = v;    }    return l;}/*============================================================================*/#endif /* USE_GC *//** Create a new atom with the given name. * * @param name the name * @return new atom */Sxpr atom_new(char *name){    Sxpr n, obj = ONOMEM;    long v;    // Don't always want to do this.    if(0 && convert_atol(name, &v) == 0){        obj = OINT(v);    } else {        n = string_new(name);        if(NOMEMP(n)) goto exit;        obj = HALLOC(ObjAtom, T_ATOM);        if(NOMEMP(obj)){            string_free(n);            goto exit;        }        OBJ_ATOM(obj)->name = n;    }  exit:    return obj;}/** Free an atom. * * @param obj to free */void atom_free(Sxpr obj){    // Interned atoms are shared, so do not free.    if(OBJ_ATOM(obj)->interned) return;    objfree(OBJ_ATOM(obj)->name);    hfree(obj);}/** Copy an atom. * * @param obj to copy */Sxpr atom_copy(Sxpr obj){    Sxpr v;    if(OBJ_ATOM(obj)->interned){        v = obj;    } else {        v = atom_new(atom_name(obj));    }    return v;}/** Print an atom. Prints the atom name. * * @param io stream to print to * @param obj to print * @param flags print flags * @return number of bytes printed */int atom_print(IOStream *io, Sxpr obj, unsigned flags){    return objprint(io, OBJ_ATOM(obj)->name, flags);}/** Atom equality. * * @param x to compare * @param y to compare * @return 1 if equal, 0 otherwise */int atom_equal(Sxpr x, Sxpr y){    int ok;    ok = eq(x, y);    if(ok) goto exit;    ok = ATOMP(y) && string_equal(OBJ_ATOM(x)->name, OBJ_ATOM(y)->name);    if(ok) goto exit;    ok = STRINGP(y) && string_equal(OBJ_ATOM(x)->name, y);  exit:    return ok;}/** Get the name of an atom. * * @param obj atom * @return name */char * atom_name(Sxpr obj){    return string_string(OBJ_ATOM(obj)->name);}int atom_length(Sxpr obj){    return string_length(OBJ_ATOM(obj)->name);}/** Get the C string from a string sxpr. * * @param obj string sxpr * @return string */char * string_string(Sxpr obj){    return OBJ_STRING(obj)->data;}/** Get the length of a string. * * @param obj string * @return length */int string_length(Sxpr obj){    return OBJ_STRING(obj)->len;}/** Create a new string. The input string is copied, * and must be null-terminated. * * @param s characters to put in the string * @return new sxpr */Sxpr string_new(char *s){    int n = (s ? strlen(s) : 0);    return string_new_n(s, n);}/** Create a new string. The input string is copied, * and need not be null-terminated. * * @param s characters to put in the string (may be null) * @param n string length * @return new sxpr */Sxpr string_new_n(char *s, int n){    Sxpr obj;    obj = halloc(sizeof(ObjString) + n + 1, T_STRING);    if(!NOMEMP(obj)){        char *str = OBJ_STRING(obj)->data;        OBJ_STRING(obj)->len = n;        if(s){            memcpy(str, s, n);            str[n] = '\0';        } else {            memset(str, 0, n + 1);        }    }    return obj;}/** Free a string. * * @param obj to free */void string_free(Sxpr obj){    hfree(obj);}/** Copy a string. * * @param obj to copy */Sxpr string_copy(Sxpr obj){    return string_new_n(string_string(obj), string_length(obj));}/** Determine if a string needs escapes when printed * using the given flags. * * @param str string to check * @param n string length * @param flags print flags * @return 1 if needs escapes, 0 otherwise */int needs_escapes(char *str, int n, unsigned flags){    char *c;    int i;    int val = 0;    if(str){        for(i=0, c=str; i<n; i++, c++){            if(in_alpha_class(*c)) continue;            if(in_decimal_digit_class(*c)) continue;            if(in_class(*c, "/._+:@~-")) continue;            val = 1;            break;        }    }    return val;}char randchar(void){    int r;    char c;    for( ; ; ){        r = rand();        c = (r >> 16) & 0xff;        if('a' <= c && c <= 'z') break;    }    return c;}int string_contains(char *s, int s_n, char *k, int k_n){    int i, n = s_n - k_n;    for(i=0; i < n; i++){        if(!memcmp(s+i, k, k_n)) return 1;    }    return 0;}int string_delim(char *s, int s_n, char *d, int d_n){    int i;    if(d_n < 4) return -1;    memset(d, 0, d_n+1);    for(i=0; i<3; i++){        d[i] = randchar();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?