Просмотр исходного кода

Merge branch '21-botgroups' into next

* 21-botgroups:
  * Fix cmd_channels showing 'inactive' on hub bots
  * Support group in cmd_channels
  * Const cleanup
  * Add command 'groups' to list all groups and which bots are in them.
  * Only match botcmd on non-hubs for groups
  * Remove unneeded botjoin/botpart
  * When overriding botset 'groups', auto include the global to avoid mistakingly making the bot part all channels immediately
  * Return the global set for default, then use the default

Conflicts:
	doc/UPDATES
Bryan Drewery 14 лет назад
Родитель
Сommit
36cccb80fe
14 измененных файлов с 135 добавлено и 116 удалено
  1. 3 0
      doc/UPDATES
  2. 13 21
      doc/help.txt
  3. 1 1
      src/chan.h
  4. 3 3
      src/chanprog.c
  5. 2 2
      src/chanprog.h
  6. 55 8
      src/cmds.c
  7. 1 1
      src/flags.c
  8. 1 1
      src/flags.h
  9. 44 27
      src/misc.c
  10. 0 46
      src/mod/channels.mod/cmdschan.c
  11. 2 2
      src/mod/irc.mod/irc.c
  12. 2 2
      src/mod/irc.mod/irc.h
  13. 7 2
      src/set.c
  14. 1 0
      src/set.h

+ 3 - 0
doc/UPDATES

@@ -4,6 +4,9 @@ next
   * Add [bot]set var 'groups' to configure what groups bots are in
   * Add chanset 'groups' to take a list of groups that should join. 'chanset #chan groups { main backup }'
   * Added group support to 'botcmd': 'botcmd %group cmd'
+  * 'botjoin' and 'botpart' have been removed. Just use .+chan, .chanset, .botset to control groups.
+  * Add command 'groups' to list all groups and which bots are in them.
+  * Command 'channels' now accepts a '%group' param to show which channels a group are in.
 
 1.4.0 - http://wraith.botpack.net/milestone/1.4.0
   * Updated server list, 'set -yes servers -' and 'set -yes servers6 -' to get new list.

+ 13 - 21
doc/help.txt

@@ -262,15 +262,6 @@ See also: -ban, +ban, console%{+m|m}, chanset, chaninfo%{-}, stick, unstick
      bl -> botcmd ?
  
 See also: cmdpass
-::botjoin
-###  $bbotjoin$b <bot> <channel> [options]
-   Adds a channel to the bot's channel list. If options are specified, the 
-   channel will be configured with the options.
- 
-   $bTHIS CMD IS CURRENTLY EXPERIMENTAL AND WILL NOT ACTUALLY SAVE STATE$b
-   $bMEANING, ALL BOTS WILL JOIN EVENTUALLY AFTER DOING BOTJOIN$b
- 
-See also: botpart, +chan, -chan, chanset, chaninfo
 :hub:botjump:
 ###  $bbotjump$b <bot> [server [port [pass]]]
    Makes the bot jump to another server. If you don't specify a
@@ -292,11 +283,6 @@ See also: msg%{+n}
    The specified bot will display its current nick over DCC.
  
 See also: netnick, nick
-::botpart
-###  $bbotpart$b <bot> <channel>
-   Removes bot from the specified channel
- 
-See also: botjoin, +chan, -chan, chanset, chaninfo
 :hub:bots
 ###  $bbots$b [nodename]
    Shows the list of bots currently on the botnet.
@@ -308,7 +294,7 @@ See also: botjoin, +chan, -chan, chanset, chaninfo
    Specifying a nodename will display all bots up/down on that nodename.
    Bots with a * preceeding its name is down.
  
-See also: downbots%{+n}, bottree%{-}
+See also: groups, downbots%{+n}, bottree%{-}
 :hub:botserver:
 ###  $bbotserver$b <bot>
    The bot will display its current server and lag over DCC.
@@ -339,7 +325,7 @@ See also: set
    Red: localhubs (first bot in binary, see '%dhelp conf')
    Other: normal leaf bots
  
-See also: bots, downbots
+See also: bots, downbots, groups
 ::botversion:
 ###  $bbotversion$b <bot>
    The bot will display its pack version and uname.
@@ -597,13 +583,14 @@ See also: %{-}%{+n}+chan, -chan%{-}%{+m|m}, chanset%{-}
  
 See also: status, whois
 ::channels:
-###  $bchannels$b %{+m}[user]%{-}
+###  $bchannels$b %{+m}[user|%group]%{-}
    Displays channels that you have access to, and any important 
    flags that are set on them.
 %{+m}
    Masters: You can specify other users to see what channels their 
             flags grant them access to.%{-}
-See also: whois%{+m}, chattr, chaninfo%{-}
+   Special %%group to see what channels a particular group is in.
+See also: whois%{+m}, chattr, chaninfo, groups%{-}
 ::chanset
 ###  $bchanset$b [#&!+channel|*|default] <settings>
    Allows you to change the channel settings (see $b'chaninfo'$b for the
@@ -654,8 +641,8 @@ See also: whois
 :hub:checkchannels
 ###  $bcheckchannels$b
    This will make all leaf bots display which channels they are currently
-   not in but *should* be in.  This command will not show channels which
-   the bot is not active in due to '$bbotpart$b'.
+   not in but *should* be in.  This will only shows channels that contain
+   the groups the bot are in.
  
 See also: botcmd, channels, channel, status
 :hub:chhandle
@@ -969,7 +956,7 @@ See also: cycle
    Example:
       Down bots: cEvin, ruthie, Killa1
  
-See also: bots
+See also: bots, groups
 :leaf:dump
 ###  $bdump$b <text>
    dumps the text to the server.  keep in mind that this bot doesn't
@@ -1066,6 +1053,11 @@ See also: -exempt, +exempt, console%{+m|m}, chanset, chaninfo%{-}, stick, unstic
    specified, your console channel is used.
  
 See also: console, channels%{+m}, status%{-}
+:hub:groups
+###  $bgroups$b
+   Shows the list of groups and which bots are in them.
+ 
+See also: bots, downbots%{+n}, bottree%{-}
 ::handle
 ###  $bhandle$b <new-handle>
    Changes your handle on the bot. This is the handle (nickname) that the

+ 1 - 1
src/chan.h

@@ -270,7 +270,7 @@ struct chanset_t {
 #define CHAN_STOP_CYCLE     BIT9	/* Some efnetservers have defined NO_CHANOPS_WHEN_SPLIT */
 
 /* prototypes */
-memberlist *ismember(struct chanset_t *, const char *);
+memberlist *ismember(const struct chanset_t *, const char *);
 struct chanset_t *findchan(const char *name);
 struct chanset_t *findchan_by_dname(const char *name);
 

+ 3 - 3
src/chanprog.c

@@ -95,7 +95,7 @@ void rmspace(char *s)
 
 /* Returns memberfields if the nick is in the member list.
  */
-memberlist *ismember(struct chanset_t *chan, const char *nick)
+memberlist *ismember(const struct chanset_t *chan, const char *nick)
 {
   register memberlist	*x = NULL;
 
@@ -743,7 +743,7 @@ int isowner(char *name)
   }
 }
 
-bool bot_shouldjoin(struct userrec* u, struct flag_record* fr, struct chanset_t* chan, bool ignore_inactive)
+bool bot_shouldjoin(struct userrec* u, struct flag_record* fr, const struct chanset_t* chan, bool ignore_inactive)
 {
   // If restarting, keep this channel.
   if (restarting && (reset_chans == 2) && (channel_active(chan) || channel_pending(chan))) return 1;
@@ -787,7 +787,7 @@ bool bot_shouldjoin(struct userrec* u, struct flag_record* fr, struct chanset_t*
       );
 }
 
-bool shouldjoin(struct chanset_t *chan)
+bool shouldjoin(const struct chanset_t *chan)
 {
   struct flag_record fr = { FR_CHAN|FR_GLOBAL|FR_BOT, 0, 0, 0 };
   get_user_flagrec(conf.bot->u, &fr, chan->dname, chan);

+ 2 - 2
src/chanprog.h

@@ -23,8 +23,8 @@ void rmspace(char *s);
 void set_chanlist(const char *host, struct userrec *rec);
 void clear_chanlist(void);
 void clear_chanlist_member(const char *nick);
-bool bot_shouldjoin(struct userrec* , struct flag_record *, struct chanset_t *, bool = 0);
-bool shouldjoin(struct chanset_t *);
+bool bot_shouldjoin(struct userrec* , struct flag_record *, const struct chanset_t *, bool = 0);
+bool shouldjoin(const struct chanset_t *);
 char *samechans(const char *, const char *);
 void add_myself_to_userlist();
 void add_child_bots();

+ 55 - 8
src/cmds.c

@@ -901,23 +901,69 @@ static void cmd_userlist(int idx, char *par)
   return;
 }
 
+static void cmd_groups(int idx, char *par)
+{
+  struct userrec *u = NULL;
+
+  putlog(LOG_CMDS, "*", "#%s# groups", dcc[idx].nick);
+
+  bd::Array<bd::String> globalgroups = bd::String(var_get_gdata("groups")).split(",");
+  bd::Array<bd::String> allgroups;
+  bd::HashTable<bd::String, bd::Array<bd::String> > groupBots;
+  bd::HashTable<bd::String, bd::Array<bd::String> > botGroups;
+  size_t maxGroupLen = 0;
+
+  // Need to loop over every bot and make a list of all groups and bots which are in those groups
+  for (u = userlist; u; u = u->next) {
+    if (u->bot && bot_hublevel(u) == 999) {
+      // Gather all the groups for this bot
+      botGroups[u->handle] = bd::String(var_get_bot_data(u, "groups", true)).split(",");
+      for (size_t i = 0; i < botGroups[u->handle].length(); ++i) {
+        const bd::String group(botGroups[u->handle][i]);
+        if (group.length() > maxGroupLen) {
+          maxGroupLen = group.length();
+        }
+        // Add their groups into the master list
+        if (allgroups.find(group) == allgroups.npos) {
+          allgroups << group;
+        }
+        // Add them to the list for this group
+        groupBots[group] << u->handle;
+
+      }
+    }
+  }
+
+  // Display all groups and which bots are in them
+  for (size_t i = 0; i < allgroups.length(); ++i) {
+    const bd::String group(allgroups[i]);
+    const bd::Array<bd::String> bots(groupBots[group]);
+    dumplots(idx, bd::String::printf("%-*s: ", int(maxGroupLen), group.c_str()).c_str(), static_cast<bd::String>(bots.join(" ")).c_str());
+  }
+
+  dprintf(idx, "Total groups: %zu\n", allgroups.length());
+  return;
+}
+
 static void cmd_channels(int idx, char *par) {
   putlog(LOG_CMDS, "*", "#%s# channels %s", dcc[idx].nick, par);
   if (par[0] && (dcc[idx].user->flags & USER_MASTER)) {
-    struct userrec *user = NULL;
-
-    user = get_user_by_handle(userlist, par);
-    if (user && whois_access(dcc[idx].user, user)) {
+    if (par[0] == '%') {
       show_channels(idx, par);
-    } else  {
-      dprintf(idx, "No such user.\n");
+    } else {
+      struct userrec *user = get_user_by_handle(userlist, par);
+      if (user && whois_access(dcc[idx].user, user)) {
+        show_channels(idx, par);
+      } else  {
+        dprintf(idx, "No such user.\n");
+      }
     }
   } else {
       show_channels(idx, NULL);
   }
 
   if ((dcc[idx].user->flags & USER_MASTER) && !(par && par[0]))
-    dprintf(idx, "You can also %schannels <user>\n", (dcc[idx].u.chat->channel >= 0) ? settings.dcc_prefix : "");
+    dprintf(idx, "You can also %schannels <user|%%group>\n", (dcc[idx].u.chat->channel >= 0) ? settings.dcc_prefix : "");
 }
 
 
@@ -1389,7 +1435,7 @@ static void cmd_botcmd(int idx, char *par)
       continue;
     cnt++;
     bool group_match = false;
-    if (botm[0] == '%') {
+    if (botm[0] == '%' && bot_hublevel(botu) == 999) {
       bd::String botgroups = var_get_bot_data(botu, "groups", true);
       if (botgroups.split(',').find(botm + 1) != bd::String::npos) {
         group_match = true;
@@ -4729,6 +4775,7 @@ cmd_t C_dcc[] =
   {"version", 		"o", 	(Function) cmd_version, 	NULL, 0},
   {"netversion", 	"o", 	(Function) cmd_netversion, 	NULL, HUB},
   {"userlist", 		"m", 	(Function) cmd_userlist, 	NULL, 0},
+  {"groups", 		"m", 	(Function) cmd_groups, 		NULL, HUB},
   {"ps", 		"n", 	(Function) cmd_ps, 		NULL, 0},
   {"last", 		"n", 	(Function) cmd_last, 		NULL, 0},
   {"exec", 		"a", 	(Function) cmd_exec, 		NULL, 0},

+ 1 - 1
src/flags.c

@@ -380,7 +380,7 @@ set_user_flagrec(struct userrec *u, struct flag_record *fr, const char *chname)
 /* Always pass the dname (display name) to this function for chname <cybah>
  */
 void
-get_user_flagrec(struct userrec *u, struct flag_record *fr, const char *chname, struct chanset_t* chan)
+get_user_flagrec(struct userrec *u, struct flag_record *fr, const char *chname, const struct chanset_t* chan)
 {
   fr->bot = 0;
   if (!u) {

+ 1 - 1
src/flags.h

@@ -142,7 +142,7 @@ struct flag_record {
 #define chan_doflood(x)				((x).chan & BOT_FLOODBOT)
 
 void init_flags(void);
-void get_user_flagrec(struct userrec *, struct flag_record *, const char *, struct chanset_t* = NULL);
+void get_user_flagrec(struct userrec *, struct flag_record *, const char *, const struct chanset_t* = NULL);
 void set_user_flagrec(struct userrec *, struct flag_record *, const char *);
 void break_down_flags(const char *, struct flag_record *, struct flag_record *);
 int build_flags(char *, struct flag_record *, struct flag_record *);

+ 44 - 27
src/misc.c

@@ -431,45 +431,62 @@ void show_motd(int idx)
 
 void show_channels(int idx, char *handle)
 {
-  struct chanset_t *chan = NULL;
-  struct flag_record fr = { FR_CHAN | FR_GLOBAL, 0, 0, 0 };
   struct userrec *u = NULL;
-  int first = 0, total = 0;
-  size_t l = 0;
-  char format[120] = "";
+  size_t maxChannelLength = 0;
+  bd::Array<bd::String> channelNames;
+  bd::HashTable<bd::String, struct chanset_t*> channels;
+  bd::String group;
 
-  if (handle)
+  if (handle && handle[0] != '%') {
     u = get_user_by_handle(userlist, handle);
-  else
+  } else {
     u = dcc[idx].user;
+    if (handle && handle[0] == '%') {
+      group = handle + 1;
+    }
+  }
 
-  for (chan = chanset;chan ;chan = chan->next) {
+  for (struct chanset_t* chan = chanset; chan; chan = chan->next) {
+    struct flag_record fr = { FR_CHAN | FR_GLOBAL, 0, 0, 0 };
+    const bd::String chname(chan->dname);
+    // If a group was passed, ensure it matches
+    if (group.length() && chan->groups->find(group) == chan->groups->npos) {
+      continue;
+    }
     get_user_flagrec(u, &fr, chan->dname);
-    if (l < strlen(chan->dname)) {
-      l = strlen(chan->dname);
+    if (group.length() || real_chk_op(fr, chan, 0)) {
+      if (maxChannelLength < chname.length()) {
+        maxChannelLength = chname.length();
+      }
+      channelNames << chname;
+      channels[chname] = chan;
     }
-    if (real_chk_op(fr, chan, 0))
-      total++;
   }
 
-  simple_snprintf(format, sizeof(format), "  %%c%%-%zus %%-s%%-s%%-s%%-s%%-s%%-s\n", (l+2));
+  if (channelNames.length()) {
+    char format[120] = "";
+    simple_snprintf(format, sizeof(format), "  %%c%%-%zus %%-s%%-s%%-s%%-s%%-s%%-s\n", (maxChannelLength+2));
+    if (group.length()) {
+      dprintf(idx, "group '%s' is in %zu channel%s:\n", group.c_str(), channelNames.length(), (channelNames.length() > 1) ? "s" : "");
+    } else {
+      dprintf(idx, "%s %s access to %zu channel%s:\n", handle ? u->handle : "You", handle ? "has" : "have", channelNames.length(), (channelNames.length() > 1) ? "s" : "");
+    }
 
-  for (chan = chanset;chan;chan = chan->next) {
-    get_user_flagrec(u, &fr, chan->dname);
-    if (real_chk_op(fr, chan, 0)) {
-        if (!first) { 
-          dprintf(idx, "%s %s access to %d channel%s:\n", handle ? u->handle : "You", handle ? "has" : "have", total, (total > 1) ? "s" : "");
-          
-          first = 1;
-        }
-        dprintf(idx, format, !conf.bot->hub && me_op(chan) ? '@' : ' ', chan->dname, !shouldjoin(chan) ? "(inactive) " : "", 
-           channel_privchan(chan) ? "(private)  " : "", chan->manop ? "(no manop) " : "", 
-           channel_bitch(chan) && !channel_botbitch(chan) ? "(bitch)    " : channel_botbitch(chan) ? "(botbitch) " : "",
-           channel_closed(chan) ?  "(closed) " : "", channel_backup(chan) ? "(backup)" : "");
+    for (size_t i = 0; i < channelNames.length(); ++i) {
+      const bd::String chname(channelNames[i]);
+      const struct chanset_t* chan = channels[chname];
+      dprintf(idx, format, !conf.bot->hub && me_op(chan) ? '@' : ' ', chan->dname, ((conf.bot->hub && channel_inactive(chan)) || (!conf.bot->hub && !shouldjoin(chan))) ? "(inactive) " : "",
+          channel_privchan(chan) ? "(private)  " : "", chan->manop ? "(no manop) " : "", 
+          channel_bitch(chan) && !channel_botbitch(chan) ? "(bitch)    " : channel_botbitch(chan) ? "(botbitch) " : "",
+          channel_closed(chan) ?  "(closed) " : "", channel_backup(chan) ? "(backup)" : "");
+    }
+  } else {
+    if (group.length()) {
+      dprintf(idx, "No channels found for group '%s'\n", group.c_str());
+    } else {
+      dprintf(idx, "%s %s not have access to any channels.\n", handle ? u->handle : "You", handle ? "does" : "do");
     }
   }
-  if (!first)
-    dprintf(idx, "%s %s not have access to any channels.\n", handle ? u->handle : "You", handle ? "does" : "do");
 }
 
 /* Create a string with random letters and digits

+ 0 - 46
src/mod/channels.mod/cmdschan.c

@@ -1008,29 +1008,6 @@ static void cmd_pls_chan(int idx, char *par)
   pls_chan(idx, par, NULL);
 }
 
-static void cmd_botjoin(int idx, char *par)
-{
-  char *bot = NULL;
-  struct userrec *botu = NULL;
-
-  putlog(LOG_CMDS, "*", "#%s# botjoin %s", dcc[idx].nick, par);
-
-  if (!par[0]) {
-    dprintf(idx, "Usage: botjoin <bot> [%s]<channel> [options]\n", CHANMETA);
-    return;
-  }
-  bot = newsplit(&par);
-  botu = get_user_by_handle(userlist, bot);
-  if (botu && botu->bot) {
-    pls_chan(idx, par, bot);
-  } else {
-    dprintf(idx, "Error: '%s' is not a bot.\n", bot);
-  }
-
-  dprintf(idx, "!!!! Warning: botjoin is an unfinished feature which will pretty much make all bots join the channel.\n");
-  dprintf(idx, "!!!! Warning: You should probably -chan the channel now to avoid problems/confusion later.\n");
-}
-
 static void mns_chan(int idx, char *par, char *bot)
 {
   char *chname = NULL, buf2[1024] = "";
@@ -1084,27 +1061,6 @@ static void cmd_mns_chan(int idx, char *par)
   mns_chan(idx, par, NULL);
 }
 
-static void cmd_botpart(int idx, char *par)
-{
-  char *bot = NULL;
-  struct userrec *botu = NULL;
-
-  putlog(LOG_CMDS, "*", "#%s# botpart %s", dcc[idx].nick, par);
-  
-  if (!par[0]) {
-    dprintf(idx, "Usage: botpart <bot> [%s]<channel> [options]\n", CHANMETA);
-    return;
-  }
-
-  bot = newsplit(&par);
-  botu = get_user_by_handle(userlist, bot);
-  if (botu && botu->bot) {
-    mns_chan(idx, par, bot);
-  } else {
-    dprintf(idx, "Error: '%s' is not a bot.\n", bot);
-  }
-}
-
 /* thanks Excelsior */
 #define FLAG_COLS 4
 static void show_flag(int idx, char *work, int *cnt, const char *name, unsigned int state, size_t worksiz)
@@ -1420,8 +1376,6 @@ static cmd_t C_dcc_channels[] =
   {"-exempt",	"o|o",	(Function) cmd_mns_exempt,	NULL, AUTH},
   {"-invite",	"o|o",	(Function) cmd_mns_invite,	NULL, AUTH},
   {"bans",	"o|o",	(Function) cmd_bans,		NULL, 0},
-  {"botjoin",	"n",	(Function) cmd_botjoin,		NULL, 0},
-  {"botpart",	"n",	(Function) cmd_botpart,		NULL, 0},
   {"exempts",	"o|o",	(Function) cmd_exempts,		NULL, 0},
   {"invites",	"o|o",	(Function) cmd_invites,		NULL, 0},
   {"chaninfo",	"m|m",	(Function) cmd_chaninfo,	NULL, 0},

+ 2 - 2
src/mod/irc.mod/irc.c

@@ -1279,7 +1279,7 @@ killmember(struct chanset_t *chan, char *nick)
 /* Check if I am a chanop. Returns boolean 1 or 0.
  */
 bool
-me_op(struct chanset_t *chan)
+me_op(const struct chanset_t *chan)
 {
   memberlist *mx = ismember(chan, botname);
 
@@ -1294,7 +1294,7 @@ me_op(struct chanset_t *chan)
 /* Check whether I'm voice. Returns boolean 1 or 0.
  */
 bool
-me_voice(struct chanset_t *chan)
+me_voice(const struct chanset_t *chan)
 {
   memberlist *mx = ismember(chan, botname);
 

+ 2 - 2
src/mod/irc.mod/irc.h

@@ -117,8 +117,8 @@ void notice_invite(struct chanset_t *, char *, char *, char *, bool);
 void real_add_mode(struct chanset_t *, const char, const char, const char *, bool);
 #define add_mode(chan, pls, mode, nick) real_add_mode(chan, pls, mode, nick, 0)
 #define add_cookie(chan, nick) real_add_mode(chan, '+', 'o', nick, 1)
-bool me_op(struct chanset_t *);
-bool me_voice(struct chanset_t *);
+bool me_op(const struct chanset_t *);
+bool me_voice(const struct chanset_t *);
 
 void check_this_ban(struct chanset_t *, char *, bool);
 void check_this_exempt(struct chanset_t *, char *, bool);

+ 7 - 2
src/set.c

@@ -525,6 +525,11 @@ static inline variable_t *var_get_var_by_name(const char *name)
   return (variable_t*) bsearch(&key, &vars, lengthof(vars) - 1, sizeof(variable_t), comp_variable_t);
 }
 
+const char *var_get_gdata(const char *name) {
+  variable_t* var = var_get_var_by_name(name);
+  return var && var->gdata ? var->gdata : NULL;
+}
+
 void var_set(variable_t *var, const char *target, const char *datain)
 {
   /* Don't set locally if the variable doesn't permit it. */
@@ -715,7 +720,7 @@ const char *var_get_bot_data(struct userrec *u, const char *name, bool useDefaul
   }
   if (useDefault) {
     variable_t *var = var_get_var_by_name(name);
-    return var->def;
+    return var->gdata ? var->gdata : var->def;
   }
   return NULL;
 }
@@ -816,7 +821,7 @@ static int var_add_list(const char *botnick, variable_t *var, const char *elemen
   char *data = NULL, *olddata = NULL, *botdata = NULL;
 
   if (botnick) {                          //fetch data from bot's USERENTRY_SET
-    botdata = (char *) var_get_bot_data(get_user_by_handle(userlist, (char *) botnick), var->name);
+    botdata = (char *) var_get_bot_data(get_user_by_handle(userlist, (char *) botnick), var->name, true);
     olddata = botdata ? botdata : NULL;
   } else                                  //use global, no bot specified
     olddata = var->gdata ? var->gdata : NULL;

+ 1 - 0
src/set.h

@@ -87,6 +87,7 @@ void init_vars();
 void var_set_by_name(const char *, const char *, const char *);
 void var_set_userentry(const char *, const char *, const char *);
 const char *var_get_bot_data(struct userrec *u, const char *name, bool useDefault = false);
+const char *var_get_gdata(const char *name);
 int cmd_set_real(const char *, int idx, char *);
 const char *var_get_str_by_name(const char *);