The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*  You may distribute under the terms of either the GNU General Public License
 *  or the Artistic License (the same terms as Perl itself)
 *
 *  (C) Paul Evans, 2009 -- leonerd@leonerd.org.uk
 */

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#ifdef HAVE_UNIBILIUM
# include <unibilium.h>
#else
# include <term.h>
#endif

static void load_terminfo(const char *termtype,
  HV *flags_by_capname, HV *nums_by_capname, HV *strs_by_capname,
  HV *flags_by_varname, HV *nums_by_varname, HV *strs_by_varname
)
{
  int i;
  SV *sv;

#ifdef HAVE_UNIBILIUM
  unibi_term *unibi = unibi_from_term(termtype);
  if(!unibi) {
    croak("unibi_from_term(\"%s\"): %s", termtype, strerror(errno));
  }
#else
  TERMINAL *oldterm = cur_term;
  setupterm(termtype, 0, NULL);
#endif

#ifdef HAVE_UNIBILIUM
  for(i = unibi_boolean_begin_+1; i < unibi_boolean_end_; i++)
#else
  for(i = 0; boolnames[i]; i++)
#endif
  {
#ifdef HAVE_UNIBILIUM
    const char *capname = unibi_short_name_bool(i);
    const char *varname = unibi_name_bool(i);
    int value = unibi_get_bool(unibi, i);
#else
    const char *capname = boolnames[i];
    const char *varname = boolfnames[i];
    int value = tigetflag(capname);
#endif

    if(!value)
      continue;

    sv = newSViv(1);
    SvREADONLY_on(sv);

    hv_store(flags_by_capname, capname, strlen(capname), sv, 0);
    hv_store(flags_by_varname, varname, strlen(varname), SvREFCNT_inc(sv), 0);
  }

#ifdef HAVE_UNIBILIUM
  for(i = unibi_numeric_begin_+1; i < unibi_numeric_end_; i++)
#else
  for(i = 0; numnames[i]; i++)
#endif
  {
#ifdef HAVE_UNIBILIUM
    const char *capname = unibi_short_name_num(i);
    const char *varname = unibi_name_num(i);
    int value = unibi_get_num(unibi, i);
#else
    const char *capname = numnames[i];
    const char *varname = numfnames[i];
    int value = tigetnum(capname);
#endif

    if(value == -1)
      continue;

    sv = newSViv(value);
    SvREADONLY_on(sv);

    hv_store(nums_by_capname, capname, strlen(capname), sv, 0);
    hv_store(nums_by_varname, varname, strlen(varname), SvREFCNT_inc(sv), 0);
  }

#ifdef HAVE_UNIBILIUM
  for(i = unibi_string_begin_+1; i < unibi_string_end_; i++)
#else
  for(i = 0; strnames[i]; i++)
#endif
  {
#ifdef HAVE_UNIBILIUM
    const char *capname = unibi_short_name_str(i);
    const char *varname = unibi_name_str(i);
    const char *value = unibi_get_str(unibi, i);
#else
    const char *capname = strnames[i];
    const char *varname = strfnames[i];
    const char *value = tigetstr(capname);
#endif

    if(!value)
      continue;

    sv = newSVpv(value, 0);
    SvREADONLY_on(sv);

    hv_store(strs_by_capname, capname, strlen(capname), sv, 0);
    hv_store(strs_by_varname, varname, strlen(varname), SvREFCNT_inc(sv), 0);
  }

#ifdef HAVE_UNIBILIUM
  unibi_destroy(unibi);
#else
  oldterm = set_curterm(oldterm);
  del_curterm(oldterm);
#endif
}

MODULE = Term::Terminfo    PACKAGE = Term::Terminfo

void
_init(self)
    HV *self

  PREINIT:
    char *termtype;
    HV *flags_by_capname, *nums_by_capname, *strs_by_capname;
    HV *flags_by_varname, *nums_by_varname, *strs_by_varname;

  CODE:
    termtype = SvPV_nolen(*hv_fetch(self, "term", 4, 0));

    flags_by_capname = newHV();
    nums_by_capname  = newHV();
    strs_by_capname  = newHV();

    flags_by_varname = newHV();
    nums_by_varname  = newHV();
    strs_by_varname  = newHV();

    load_terminfo(termtype,
      flags_by_capname, nums_by_capname, strs_by_capname,
      flags_by_varname, nums_by_varname, strs_by_varname
    );

    hv_store(self, "flags_by_capname", 16, newRV_noinc((SV*)flags_by_capname), 0);
    hv_store(self, "nums_by_capname",  15, newRV_noinc((SV*)nums_by_capname),  0);
    hv_store(self, "strs_by_capname",  15, newRV_noinc((SV*)strs_by_capname),  0);

    hv_store(self, "flags_by_varname", 16, newRV_noinc((SV*)flags_by_varname), 0);
    hv_store(self, "nums_by_varname",  15, newRV_noinc((SV*)nums_by_varname),  0);
    hv_store(self, "strs_by_varname",  15, newRV_noinc((SV*)strs_by_varname),  0);

    XSRETURN_UNDEF;