da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1985-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* http://www.opensource.org/licenses/cpl1.0.txt *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Glenn Fowler <gsf@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Phong Vo <kpv@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * tsearch() for systems that have <search.h> but no tsearch()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * why would such a system provide the interface but not the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * implementation? that's what happens when one slimes their
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * way through standards compliance
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * NOTE: please excuse the crude feature test
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if !_UWIN
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid _STUB_tsearch(){}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if _PACKAGE_ast
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <ast.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define tdelete ______tdelete
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define tfind ______tfind
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define tsearch ______tsearch
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define twalk ______twalk
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <search.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef tdelete
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef tfind
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef tsearch
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef twalk
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "dthdr.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* POSIX tsearch library based on libcdt
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** Written by Kiem-Phong Vo (AT&T Research, 07/19/95)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct _tree_s
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{ Dtlink_t link;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Void_t* key;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin} Tree_t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chintypedef struct _treedisc_s
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{ Dtdisc_t disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int(* comparf)_ARG_((const Void_t*, const Void_t*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin} Treedisc_t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(__EXPORT__)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define extern __EXPORT__
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* compare function */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int treecompare(Dt_t* dt, char* one, char* two, Dtdisc_t* disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int treecompare(dt, one, two, disc)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinDt_t* dt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinchar* one;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinchar* two;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinDtdisc_t* disc;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (*((Treedisc_t*)disc)->comparf)((Void_t*)one,(Void_t*)two);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic Treedisc_t Treedisc =
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{ { sizeof(Dtlink_t), -1, /* object is key */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 0,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NIL(Dtmake_f), NIL(Dtfree_f),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin treecompare,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NIL(Dthash_f),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NIL(Dtmemory_f),
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NIL(Dtevent_f)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin },
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin 0
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinextern
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* tsearch(const Void_t* key, Void_t** rootp,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int(*comparf)(const Void_t*,const Void_t*) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* tsearch(key, rootp, comparf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* key;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t** rootp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint(* comparf)();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Dt_t* dt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Tree_t* o;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!rootp ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (!(dt = *((Dt_t**)rootp)) && !(dt = dtopen((Dtdisc_t*)(&Treedisc),Dtorder))) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* dangerous to set comparf on each call but that's tsearch */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Treedisc.comparf = comparf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(o = (Tree_t*)dtmatch(dt,key)) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { if(!(o = (Tree_t*)malloc(sizeof(Tree_t))) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin o->key = (Void_t*)key;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dtinsert(dt,o);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(o)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *rootp = (Void_t*)dt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(*rootp == NIL(Void_t*) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dtclose(dt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (Void_t*)(&o->key);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinextern
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* tfind(const Void_t* key, Void_t*const* rootp,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int(*comparf)(const Void_t*, const Void_t*) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* tfind(key, rootp, comparf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* key;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t** rootp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint(* comparf)();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Dt_t* dt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Tree_t* o;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!rootp || !(dt = *((Dt_t**)rootp)) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Treedisc.comparf = comparf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (o = (Tree_t*)dtmatch(dt,key)) ? (Void_t*)(&o->key) : NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* the original tdelete() specifies that it will return the parent pointer
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** in the tree if there is one. Since we are using a splay tree, a deleted
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** node is always rotated to the root first. So this implementation always
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** returns the key of the new root.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinextern
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* tdelete(const Void_t* key, Void_t** rootp,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int(*comparf)(const Void_t*, const Void_t*) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* tdelete(key, rootp, comparf)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* key;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t** rootp;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint(* comparf)();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Dt_t* dt;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Tree_t* o;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Tree_t obj;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!rootp || !(dt = *((Dt_t**)rootp)) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin Treedisc.comparf = comparf;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin obj.key = (Void_t*)key;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin dtdelete(dt,&obj);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(o = dtfinger(dt)) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { dtclose(dt);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *rootp = NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return o ? (Void_t*)(&o->key) : NIL(Void_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* the below routine assumes a particular layout of Dtlink_t.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** If this ever gets changed, this routine should be redone.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define lchild link.hl._left
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define rchild link.right
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void _twalk(Tree_t* obj, void(*action)(const Void_t*,VISIT,int), int level)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void _twalk(obj,action,level)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinTree_t* obj;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid(* action)();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint level;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{ if(!obj->lchild && !obj->rchild)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*action)((Void_t*)obj,leaf,level);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { (*action)((Void_t*)obj,preorder,level);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(obj->lchild)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin _twalk((Tree_t*)obj->lchild,action,level+1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*action)((Void_t*)obj,postorder,level);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(obj->rchild)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin _twalk((Tree_t*)obj->rchild,action,level+1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (*action)((Void_t*)obj,endorder,level);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* the original twalk allows specifying arbitrary node to start traversal.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** Since our root is a dictionary structure, the search here will start
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin** at whichever node happens to be current root.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin*/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinextern
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if __STD_C
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid twalk(const Void_t* root, void(*action)(const Void_t*,VISIT,int) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid twalk(root, action)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinVoid_t* root;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid(* action)();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin reg Tree_t* o;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(root && (o = (Tree_t*)dtfinger((Dt_t*)root)) )
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin _twalk(o,action,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif