/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMud ROM Derivative (c) 2001-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#ifndef __MACRO_H_
#define __MACRO_H_ 1
#ifndef PARAMS
# if defined PROTOTYPES || defined WIN32
# define PARAMS(protos) protos
# else
# define PARAMS(protos) ()
# define __attribute__(x)
# endif
#endif
#ifndef __attribute__
# define __attribute__(x)
#endif
#define Proto(x,y) EXTERN x PARAMS(y)
#define ProtoF(x,y,a,b) EXTERN x PARAMS(y) __attribute__((format(printf, a, b)))
#define ProtoNoR(x, y) EXTERN x PARAMS(y) __attribute__((noreturn))
#define alloc_mem(result, type, number) \
do { \
if (!((result) = (type *) calloc ((number), sizeof(type)))) { \
logf( "Malloc failure @ %s:%d", __FILE__, __LINE__ ); \
abort(); \
} \
} while(0)
#define realloc_mem(result,type,number) \
do { \
if (!((result) = (type *) realloc ((void *)(result), sizeof(type) * (number)))) { \
logf( "Realloc failure @ %s:%d", __FILE__, __LINE__ ); \
abort(); \
} \
} while(0)
#define free_mem(point) \
do { \
if (!(point)) \
bugf("Freeing null pointer %s:%d", __FILE__, __LINE__ ); \
else free((void *)(point)); \
(point) = NULL; \
} while(0)
#define IsValid(data) ((data) != NULL && (data)->valid)
#define Validate(data) ((data)->valid = true)
#define Invalidate(data) ((data)->valid = false)
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Diff(a, b) ((a > b) ? (a - b) : (b - a))
#define Range(a, b, c) ((b) < (a) ? (a) : ((b) > (c) ? (c) : (b)))
#define Percent(a, b) Min(100 * (a) / (b), 100)
#define IsSet(flag, bit) ((flag) & (bit))
#define SetBit(var, bit) ((var) |= (bit))
#define RemBit(var, bit) ((var) &= ~(bit))
#define DiffBit(flag, bit) ((flag) & ~(bit))
#define ToggleBit(var, bit) ((var) ^= (bit))
#define GetUnset(flag1,flag2) (~(flag1)&((flag1)|(flag2)))
#define GetDiff(a,b) (~((~a)|(b)))
#define DiffBit(flag, bit) ((flag) & ~(bit))
#define RepBit(flag, a, b) (((flag) & ~(a)) | (b))
#define StrIsSet(var, bit) ((((char *)(var))[((bit)/8)]) & ((1<<((bit)%8))))
#define StrSetBit(var, bit) ((((char *)(var))[((bit)/8)]) |= ((1<<((bit)%8))))
#define StrRemBit(var, bit) ((((char *)(var))[((bit)/8)]) &= ~((1<<((bit)%8))))
#define StrToggleBit(var, bit) ((((char *)(var))[((bit)/8)]) ^= ((1<<((bit)%8))))
#define NullStr(str) (!(str) || !*(str))
#define Entre(min,num,max) ( ((min) < (num)) && ((num) < (max)) )
#define CheckPos(a, b, c) \
do { \
(a) = (b); \
if ( (a) < 0 ) \
bug( "CheckPos : " c " == < 0"); \
} while(0)
#define SetStat(ch, pos, val) ((ch)->pcdata->gamestat[pos] = val)
#define GetStat(ch, pos) ((ch)->pcdata->gamestat[pos])
#define AddStat(ch, pos, val) ((ch)->pcdata->gamestat[pos] += val)
#define ValidStance(st) ((st) > STANCE_NONE && (st) < STANCE_CURRENT)
#define GetStance(ch, st) ((ch)->stance[(st)])
#define InStance(ch, sn) (GetStance((ch), STANCE_CURRENT) == (sn))
#define SetStance(ch, pos, st) ((ch)->stance[(pos)] = (st))
#define Str(x) #x
#define Stringify(x) Str(x)
#define UnlinkSingle(point,type,list,next) \
do { \
if (list == point) \
list = point->next; \
else { \
type *prev; \
for (prev = list; prev != NULL; prev = prev->next) { \
if (prev->next == point) { \
prev->next = point->next; \
break; \
} \
} \
if (prev == NULL) \
bugf (#point " not found in " #list "."); \
} \
} while(0)
#define LinkSingle(point,list,next) \
do { \
point->next = list; \
list = point; \
} \
while (0)
#define LinkLast(type,point,list,next) \
do { \
type *tmp; \
if((tmp = list) == NULL) { \
point->next = list; \
list = point; \
break; \
} \
for(; tmp; tmp = tmp->next) { \
if(!tmp->next) { \
tmp->next = point; \
point->next = NULL; \
break; \
} \
} \
} \
while (0)
#define Link(link, name, next, prev) \
do { \
if ( !(name##_first) ) { \
(name##_first) = (link); \
(name##_last) = (link); \
} \
else \
(name##_last)->next = (link); \
(link)->next = NULL; \
if (name##_first == link) \
(link)->prev = NULL; \
else \
(link)->prev = (name##_last); \
(name##_last) = (link); \
} while(0)
#define Insert(link, insert, name, next, prev) \
do { \
(link)->prev = (insert)->prev; \
if ( !(insert)->prev ) \
(name##_first) = (link); \
else \
(insert)->prev->next = (link); \
(insert)->prev = (link); \
(link)->next = (insert); \
} while(0)
#define UnLink(link, name, next, prev) \
do { \
if ( !(link)->prev ) { \
(name##_first) = (link)->next; \
if ((name##_first)) \
(name##_first)->prev = NULL; \
} \
else { \
(link)->prev->next = (link)->next; \
} \
if ( !(link)->next ) { \
(name##_last) = (link)->prev; \
if ((name##_last)) \
(name##_last)->next = NULL; \
} \
else { \
(link)->next->prev = (link)->prev; \
} \
} while(0)
#define CheckLinks(type, name, next, prev) \
do { \
type *ptr, *pptr = NULL; \
if ( !(name##_first) && !(name##_last) ) \
break; \
if ( !(name##_first) ) { \
bugf( "CheckLinks: name##_last with NULL name##_first! %s.", \
#name##_first ); \
for ( ptr = (name##_last); ptr->prev; ptr = ptr->prev ); \
(name##_first) = ptr; \
} \
else if ( !(name##_last) ) { \
bugf( "CheckLinks: name##_first with NULL name##_last! %s.", \
#name##_first ); \
for ( ptr = (name##_first); ptr->next; ptr = ptr->next ); \
(name##_last) = ptr; \
} \
if ( (name##_first) ) { \
for ( ptr = (name##_first); ptr; ptr = ptr->next ) { \
if ( ptr->prev != pptr ) { \
bugf( "CheckLinks(%s): %p:->prev != %p. Fixing.", \
#name##_first, ptr, pptr ); \
ptr->prev = pptr; \
} \
if ( ptr->prev && ptr->prev->next != ptr ) { \
bugf( "CheckLinks(%s): %p:->prev->next != %p. Fixing.", \
#name##_first, ptr, ptr ); \
ptr->prev->next = ptr; \
} \
pptr = ptr; \
} \
pptr = NULL; \
} \
if ( (name##_last) ) { \
for ( ptr = (name##_last); ptr; ptr = ptr->prev ) { \
if ( ptr->next != pptr ) { \
bugf( "CheckLinks (%s): %p:->next != %p. Fixing.", \
#name##_first, ptr, pptr ); \
ptr->next = pptr; \
} \
if ( ptr->next && ptr->next->prev != ptr ) { \
bugf( "CheckLinks(%s): %p:->next->prev != %p. Fixing.", \
#name##_first, ptr, ptr ); \
ptr->next->prev = ptr; \
} \
pptr = ptr; \
} \
} \
} while(0)
#define NUL '\0'
#define GetStr(str, msg) (NullStr(str) ? (msg) : (str))
#define IsNPC(ch) (IsSet((ch)->act, ACT_IS_NPC))
#define IsImmortal(ch) (get_trust(ch) >= LEVEL_IMMORTAL)
#define IsPlayer(ch) (!IsNPC(ch) && !IsImmortal(ch))
#define IsHero(ch) (get_trust(ch) >= LEVEL_HERO)
#define IsTrusted(ch,level) (get_trust((ch)) >= (level))
#define IsAffected(ch, sn) (IsSet((ch)->affected_by, (sn)))
#define IsDrunk(ch) (!IsNPC(ch) && (ch)->pcdata->condition[COND_DRUNK] > 10)
#define IsGood(ch) (ch->alignment >= 350)
#define IsEvil(ch) (ch->alignment <= -350)
#define IsNeutral(ch) (!IsGood(ch) && !IsEvil(ch))
#define IsAway(ch) (IsSet((ch)->comm,COMM_AFK))
#define IsAwake(ch) (ch->position > POS_SLEEPING)
#define GetArmor(ch,type) ((ch)->armor[type] + ( IsAwake(ch) \
? dex_app[get_curr_stat(ch,STAT_DEX)].defensive : 0 ))
#define TrueSex(ch) (!IsNPC(ch) ? (ch)->pcdata->true_sex : (ch)->sex)
#define GetHitroll(ch) ((ch)->hitroll+str_app[get_curr_stat(ch,STAT_STR)].tohit)
#define GetDamroll(ch) ((ch)->damroll+str_app[get_curr_stat(ch,STAT_STR)].todam)
#define IsOutside(ch) (!IsSet((ch)->in_room->room_flags, ROOM_INDOORS))
#define InWar(ch) (ch->war != NULL && IsSet((ch)->in_room->room_flags, ROOM_ARENA))
#define WaitState(ch, npulse) ((ch)->wait = Max((ch)->wait, (npulse)))
#define DazeState(ch, npulse) ((ch)->daze = Max((ch)->daze, (npulse)))
#define get_carry_weight(ch) ((ch)->carry_weight + (int)((ch)->silver/10 + \
(ch)->gold * 2 / 5))
#define act(format,ch,arg1,arg2,type) \
act_new((format),(ch),(arg1),(arg2),(type),POS_RESTING)
#define log_wiznet(fmt, ch, obj, flag, level) \
new_wiznet((ch), (obj),(flag),true,(level), (fmt))
#define wiznet(string, ch, obj, flag, logit, level) \
new_wiznet((ch),(obj),(flag),(logit),(level),(string))
#define HasTriggerMob(ch,trig) (IsSet((ch)->pIndexData->mprog_flags,(trig)))
#define HasTriggerObj(obj,trig) (IsSet((obj)->pIndexData->oprog_flags,(trig)))
#define HasTriggerRoom(room,trig) (IsSet((room)->rprog_flags,(trig)))
#define IsSwitched( ch ) ( ch->desc && ch->desc->original )
#define IsBuilder(ch, Area) ( !IsNPC(ch) && !IsSwitched( ch ) && \
( ch->pcdata->security >= Area->security \
|| strstr( Area->builders, ch->name ) \
|| strstr( Area->builders, "All" ) ) )
#define CH(descriptor) ((descriptor)->original ? \
(descriptor)->original : (descriptor)->character)
#define IsRemort(ch) ((ch)->Class[CLASS_COUNT] > 1)
#define GetRemort(ch) (Max(0, (ch)->Class[CLASS_COUNT] - 1))
#define ClassName(ch, i) (class_table[(i)].name[GetRemort(ch)])
#define LinkDead(ch) (!IsNPC(ch) && (ch)->desc == NULL)
#define Gquester(ch) (gquest_info.running != GQUEST_OFF && (ch)->gquest)
#define StrEdKey(ch) (IsNPC(ch) ? '.' : (ch)->pcdata->str_ed_key)
#define GetTzone(ch) (IsNPC(ch) ? -1 : (ch)->pcdata->timezone)
#define AreaClan(area) ((area)->clan)
#define CharClan(ch) (IsNPC(ch) ? AreaClan((ch)->pIndexData->area) : (ch)->pcdata->clan)
#define ObjClan(obj) (AreaClan((obj)->pIndexData->area))
#define RoomClan(room) (AreaClan((room)->area))
#define IsPortal(d) ((d) && IsSet((d)->desc_flags, DESC_PORTAL))
#define IsFireCl(d) ((d) && IsSet((d)->desc_flags, DESC_IMP))
#define IsMXP(d) ((d) && IsSet((d)->desc_flags, DESC_MXP) \
&& ((d)->mxp.mxp_ver * 10) >= 4)
#define IsMSP(d) ((d) && IsSet((d)->desc_flags, DESC_MSP))
#define IsCompressed(d) (d && d->out_compress)
#define IsPueblo(d) ((d) && IsSet((d)->desc_flags, DESC_PUEBLO))
#define ScrWidth(d) (!(d) ? DEFAULT_SCR_WIDTH : (d)->scr_width)
#define ScrHeight(d) (!(d) ? DEFAULT_SCR_HEIGHT : (d)->scr_height)
#define VT100_SET(ch, fl) ((ch) && (ch)->pcdata && \
IsSet((ch)->pcdata->vt100, VT100_##fl))
#define HasTimer(ch, pos) (!IsNPC(ch) && (ch)->pcdata->timers[pos] > 0)
#define SetTimer(ch, pos, val) ((ch)->pcdata->timers[pos] = (val))
#define ClearTimer(ch, pos) ((ch)->pcdata->timers[pos] = 0)
#define GetTimer(ch, pos) ((ch)->pcdata->timers[pos])
#define UpdateTimer(ch, pos) (--(ch)->pcdata->timers[pos] <= 0)
#define ObjFlag(obj, flag) (IsSet((obj)->extra_flags, (flag)))
#define PlrFlag(ch, flag) (!IsNPC(ch) && IsSet((ch)->act, (flag)))
#define DescrFlag(d, flag) (IsSet((d)->desc_flags, (flag)))
#define MobFlag(ch, flag) (IsNPC(ch) && IsSet((ch)->act, (flag)))
#define CommFlag(ch, flag) (IsSet((ch)->comm, (flag)))
#define RoomFlag(loc, flag) (IsSet((loc)->room_flags, (flag)))
#define ExitFlag(ex, flag) (IsSet((ex)->exit_info, (flag)))
#define AreaFlag(loc, flag) (IsSet((loc)->area_flags, (flag)))
#define ClanFlag(clan, flag) (IsSet((clan)->clan_flags, (flag)))
#define RaceFlag(race, flag) (IsSet((race)->race_flags, (flag)))
#define SkillFlag(skill, flag) (IsSet(skill_table[(skill)].flags, (flag)))
#define GroupFlag(group, flag) (IsSet(group_table[(group)].flags, (flag)))
#define MudFlag(flag) (IsSet(mud_info.mud_flags, (flag)))
#define VideoFlag(ch, flag) ((ch) && !IsNPC(ch) && IsSet((ch)->pcdata->video, (flag)))
#define TouchArea(area) (SetBit((area)->area_flags, OLC_CHANGED))
#define QuestObj(obj) (IsSet(obj->extra_flags, ITEM_QUEST))
#define OnOff(a) ((a) ? "{WON" : "{ROFF")
#define YesNo(a) ((a) ? "{WYES" : "{RNO")
#define CanWear(obj, part) (IsSet((obj)->wear_flags, (part)))
#define IsObjStat(obj, stat) (IsSet((obj)->extra_flags, (stat)))
#define IsWeaponStat(obj,stat) (IsSet((obj)->value[4],(stat)))
#define WeightMult(obj) ((obj)->item_type == ITEM_CONTAINER ? \
(obj)->value[4] : 100)
#define IsQuester(ch) (!IsNPC(ch) && (ch)->pcdata->quest.status != QUEST_NONE )
#define Season (((time_info.month / 4) > 3) ? 3 : (time_info.month / 4))
#define IsAlternate(ch,victim) (!IsNPC(ch) && !IsNPC(victim) \
&& ch->desc && victim->desc \
&& ch != victim && !str_cmp(ch->desc->host, \
victim->desc->host))
#define GetName(ch) (IsNPC(ch) ? (ch)->short_descr : (ch)->name)
#define PretitOK(ch, looker) (!IsNPC(ch) && !NullStr((ch)->pcdata->pretit) \
&& (looker) && !IsSet((looker)->comm, COMM_NOPRETITLE))
#define Pers(ch, looker) ( can_see( looker, (ch) ) ? \
PretitOK((ch), looker) ? \
FORMATF("%s %s", (ch)->pcdata->pretit, \
(ch)->name) : GetName(ch) \
: IsImmortal(ch) ? "an Immortal" : "someone" )
#define VnumID(ch) (IsNPC(ch) ? (ch)->pIndexData->vnum : (ch)->id)
#define Key_Array( literal, array, max, def ) \
if ( !str_cmp( word, literal ) ) { \
read_array(fp, array, max, def); \
fMatch = true; \
break; \
}
#define Key_Ignore(literal) \
if ( !str_cmp(word, literal ) ) { \
read_to_eol(fp); \
fMatch = true; \
break; \
}
#define Key_Do(literal, dothis) \
if (!str_cmp(word, literal ) ) { \
dothis; \
read_to_eol(fp); \
fMatch = true; \
break; \
}
#define Key_Time( literal, field) \
if ( !str_cmp( word, literal ) ) { \
read_time(fp, &field); \
fMatch = true; \
break; \
}
#define Key( literal, field, value ) \
if ( !str_cmp( word, literal ) ) { \
field = value; \
read_to_eol(fp); \
fMatch = true; \
break; \
}
#define Key_Str( literal, field ) \
if ( !str_cmp( word, literal ) ) { \
read_strfree(fp, &field); \
read_to_eol(fp); \
fMatch = true; \
break; \
}
#define Key_SFun( literal, field, strfun ) \
if ( !str_cmp( word, literal ) ) { \
const char *tmp = read_string(fp); \
field = strfun(tmp); \
free_string(tmp); \
fMatch = true; \
break; \
}
#define Key_StrCpy( literal, field ) \
if ( !str_cmp( word, literal ) ) { \
const char *tmp = read_string(fp); \
strncpy(field, tmp, sizeof(field)); \
free_string(tmp); \
read_to_eol(fp); \
fMatch = true; \
break; \
}
#define write_array(fp, name, format, array, max) \
do { \
int tmp; \
if(NullStr(name)) \
f_printf(fp, "%d", max); \
else \
f_writef(fp, name, "%d", max); \
for(tmp = 0; tmp < max; tmp++) \
f_printf(fp, " " format, array[tmp]); \
if(!NullStr(name)) \
f_printf(fp, LF); \
} while(0)
#define read_array(fp, array, max, def) \
do { \
int tmp = 0, tmpmax = read_number(fp); \
while(tmp < Min(max, tmpmax)) \
array[tmp++] = read_number(fp); \
read_to_eol(fp); \
while(tmp < max) \
array[tmp++] = def; \
} while(0)
#define write_int(fp, name, format, var, def) \
do { \
if(NullStr(name)) \
f_printf((fp), format LF, (var)); \
else if ((var) != (def)) \
f_writef((fp), (name), format LF, (var)); \
} while(0)
#define copy_array(array1, array2, aMax) \
do { int a; \
for(a = 0; a < aMax; a++) \
array1[a] = array2[a]; \
} while(0)
#define set_array(ar, v, mx) \
do { int _a; \
for(_a = 0; _a < mx; _a++) \
ar[_a] = v; \
} while(0)
#define read_enum(type, fp) (type)read_number(fp)
#define atov atol
#define read_vnum (vnum_t) read_long
#define atom (money_t) atol
#define read_money (money_t) read_long
#define titlebar(ch, str) stringf(ch, 0, Center, "-=", str)
#define titlewidth(len, str) stringf(NULL, len, Center, "-=", str)
#define titlefill(len, fill, str) stringf(NULL, len, Center, fill, str)
#define str_width(width, str) stringf(NULL, width, Left, NULL, str)
#define str_align(len, align, str) stringf(NULL, len, align, NULL, str)
#define str_fill(len, fill) FORMATF("%-*c", len, fill)
#define help_text(txt) ((txt)[0] == '.' ? (txt) + 1 : (txt))
#ifdef WIN32
#define vsnprintf _vsnprintf
#define snprintf _snprintf
#define getpid _getpid
#define random() rand()
#define srandom( x ) srand( x )
#define STDERR_FILENO 2
#define S_ISREG(mode) ((mode) & S_IFREG)
#define S_ISDIR(mode) ((mode) & S_IFDIR)
#define strcasecmp stricmp
#define strncasecmp strnicmp
#define socket_error(text) logf("%s: %s", get_winsock_error_text(0), text)
#define makedir(dir) mkdir(dir)
#define check_errno(err) (WSAGetLastError() == WSA##err)
#define sockerrno WSAGetLastError()
#define popen _popen
#define pclose _pclose
#else
#define closesocket close
#define socket_error log_error
#define sockerrno errno
#define check_errno(err) (errno == err)
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR -1
#define makedir(dir) mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
#define SOCKADDR struct sockaddr
#ifndef HAVE_ATEXIT
#define exit(err) \
do { \
if(run_level == RUNLEVEL_MAIN_LOOP) \
exit_mud(); \
_exit(err); \
} while(0)
#endif
#endif
#define add_text(text, to) \
do { \
char *code = text; \
while (*code != '\0') { \
*to = *code++; \
*++to = '\0'; \
} \
} while(0)
#ifdef IN_DB_C
#define GLOBAL(str) str
#define GLOBAL_DEF(str, def) str = def
#define GLOBAL_INFO(type, str) \
type str##_info, str##_zero; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#define GLOBAL_STRUCT(type, str) \
type *str##_free = NULL, str##_zero; \
int top_##str = 0, top_##str##_free = 0; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#define GLOBAL_TABLE(type, str, table) \
type *str##_free = NULL, str##_zero, *str##_##table; \
int top_##str = 0, top_##str##_free = 0; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#define GLOBAL_LIST(type, str) \
type * str##_first = NULL, * str##_last = NULL, str##_zero, *str##_free = NULL; \
int top_##str = 0, top_##str##_free = 0; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#else
#define GLOBAL(str) EXTERN str
#define GLOBAL_DEF(str, def) EXTERN str
#define GLOBAL_INFO(type, str) \
EXTERN type str##_info, str##_zero; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#define GLOBAL_STRUCT(type, str) \
EXTERN type *str##_free, str##_zero; \
EXTERN int top_##str, top_##str##_free; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#define GLOBAL_TABLE(type, str, table) \
EXTERN type *str##_free, str##_zero, *str##_##table; \
EXTERN int top_##str, top_##str##_free; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#define GLOBAL_LIST(type, str) \
EXTERN type *str##_first, *str##_last, str##_zero, *str##_free; \
EXTERN int top_##str, top_##str##_free; \
EXTERN TableSave_F rw_##str##_data; \
EXTERN DataTable str##_data_table[]
#endif
#endif