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 + -
显示快捷键?