#include #include #include #include #include #include #include #include #include #include #include #include #include "tlmplib.h" #include "tlmplib.m" static TLMP_OPTION *first = NULL; class TLMP_OPTION_private{ public: bool ison; // Option has been selected by the user SSTRING name; TRANS_NOTLOAD *desc; TLMP_OPTION *next; SSTRING *str; SSTRINGS *strs; int *val; int (*fct)(); int (*fctval)(const char*); void init ( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt) { name = _name; desc = _desc; next = first; first = opt; ison = false; str = NULL; strs = NULL; val = NULL; fct = NULL; fctval = NULL; } TLMP_OPTION_private( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt) { init (_name,_desc,opt); } TLMP_OPTION_private( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt, int (*_fct)()) { init (_name,_desc,opt); fct = _fct; } TLMP_OPTION_private( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt, int (*_fctval)(const char *)) { init (_name,_desc,opt); fctval = _fctval; } TLMP_OPTION_private( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt, SSTRING &s) { init (_name,_desc,opt); str = &s; } TLMP_OPTION_private( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt, SSTRINGS &s) { init (_name,_desc,opt); strs = &s; } TLMP_OPTION_private( const char *_name, TRANS_NOTLOAD *_desc, TLMP_OPTION *opt, int &s) { init (_name,_desc,opt); val = &s; } }; PUBLIC TLMP_OPTION::TLMP_OPTION( const char *optname, TRANS_NOTLOAD *optdesc) { priv = new TLMP_OPTION_private (optname,optdesc,this); } PUBLIC TLMP_OPTION::TLMP_OPTION( const char *optname, TRANS_NOTLOAD *optdesc, int (*fct)()) { priv = new TLMP_OPTION_private (optname,optdesc,this,fct); } PUBLIC TLMP_OPTION::TLMP_OPTION( const char *optname, TRANS_NOTLOAD *optdesc, int (*fct)(const char*)) { priv = new TLMP_OPTION_private (optname,optdesc,this,fct); } PUBLIC TLMP_OPTION::TLMP_OPTION( const char *optname, TRANS_NOTLOAD *optdesc, SSTRING &s) { priv = new TLMP_OPTION_private (optname,optdesc,this,s); } PUBLIC TLMP_OPTION::TLMP_OPTION( const char *optname, TRANS_NOTLOAD *optdesc, SSTRINGS &s) { priv = new TLMP_OPTION_private (optname,optdesc,this,s); } PUBLIC TLMP_OPTION::TLMP_OPTION( const char *optname, TRANS_NOTLOAD *optdesc, int &s) { priv = new TLMP_OPTION_private (optname,optdesc,this,s); } PUBLIC TLMP_OPTION::~TLMP_OPTION() { TLMP_OPTION **prev = &first; while (*prev != NULL){ if (*prev == this){ *prev = priv->next; break; } } delete priv; } PUBLIC const char *TLMP_OPTION::getname() const { return priv->name.get(); } PUBLIC const char *TLMP_OPTION::getdesc() const { return priv->desc->get(); } PUBLIC TLMP_OPTION *TLMP_OPTION::getnext() const { return priv->next; } PUBLIC bool TLMP_OPTION::ison() const { return priv->ison; } PUBLIC bool TLMP_OPTION::needval() const { return priv->str != NULL || priv->strs != NULL || priv->val != NULL || priv->fctval != NULL; } PUBLIC int TLMP_OPTION::setval(const char *val) { int ret = -1; const char *name = getname(); if (priv->str != NULL){ if (priv->ison){ fprintf (stderr,MSG_U(E_NOOPTREP,"Option %s must be used only once\n") ,name); }else{ priv->str->setfrom(val); priv->ison = true; ret = 0; } }else if (priv->strs != NULL){ priv->strs->add (val); priv->ison = true; ret = 0; }else if (priv->val != NULL){ if (priv->ison){ fprintf (stderr,MSG_R(E_NOOPTREP),name); }else if (val != NULL && (val[0] == '-' || isdigit(val[0]))){ *priv->val = atoi(val); ret = 0; priv->ison = true; }else{ fprintf (stderr,MSG_U(E_OPTNUM,"Option %s, numeric value required\n") ,name); } }else if (priv->fctval != NULL){ ret = priv->fctval(val); priv->ison = true; }else if (val != NULL){ fprintf (stderr,MSG_U(E_NOVALUE,"Option %s does not accept any value\n") ,name); }else{ priv->ison = true; ret = 0; if (priv->fct != NULL) ret = priv->fct(); } return ret; } static void tlmp_usage_other() { TLMP_OPTION *pt = first; // Here we go straight to stdout, since this usage is only displayed on // explicit request. FILE *fd = stdout ; while (pt != NULL){ fprintf (fd, " --%-20s %s\n",pt->getname(),pt->getdesc()); pt = pt->getnext(); } } class TLMPARG: public ARRAY_OBJ{ public: char letter; const char *name; const char *desc; SSTRING defval; enum ARG_TYPE{ ARG_PTSTR,ARG_STRING,ARG_INT,ARG_BOOL,ARG_STRINGS,ARG_GROUP } type; union { const char **valptstr; SSTRING *valstr; SSTRINGS *valstrs; int *valint; bool *valbool; }; bool mandatory; bool seen; void init () { seen = false; } TLMPARG(const char *_desc) { init(); mandatory = false; letter = '\0'; name = ""; desc = _desc; valint = NULL; type = ARG_GROUP; } TLMPARG(char _letter, const char *_name, const char *_desc, const char *&_val, bool _mandatory) { init(); mandatory = _mandatory; letter = _letter; name = _name; desc = _desc; valptstr = &_val; type = ARG_PTSTR; if (*valptstr != NULL) defval = *valptstr; } TLMPARG(char _letter, const char *_name, const char *_desc, SSTRING &_val, bool _mandatory) { init(); mandatory = _mandatory; letter = _letter; name = _name; desc = _desc; valstr = &_val; defval = _val; type = ARG_STRING; } TLMPARG(char _letter, const char *_name, const char *_desc, SSTRINGS &_vals, bool _mandatory) { init(); mandatory = _mandatory; letter = _letter; name = _name; desc = _desc; valstrs = &_vals; const char *ctl = "%s"; for (int i=0; i<_vals.size(); i++){ defval.appendf (ctl,_vals.getitem(i)->get()); ctl = ",%s"; } type = ARG_STRINGS; } TLMPARG(char _letter, const char *_name, const char *_desc, int &_val, bool _mandatory) { init(); mandatory = _mandatory; letter = _letter; name = _name; desc = _desc; valint = &_val; defval.setfromf ("%d",_val); type = ARG_INT; } TLMPARG(char _letter, const char *_name, const char *_desc, bool &_val, bool _mandatory) { init(); mandatory = _mandatory; letter = _letter; name = _name; desc = _desc; valbool = &_val; type = ARG_BOOL; } }; class TLMPARGS: public ARRAY{ public: TLMPARG *getitem(int no) const { return (TLMPARG*)ARRAY::getitem(no); } }; struct _F_tlmpprogram___v0_private{ SSTRING progname,version,desc; SSTRING dbname; TLMPARGS args; FILE *usage_fd; }; void _F_tlmpprogram___v0::setdbconfname(const char *dbname) { priv->dbname.setfrom (dbname); } void _F_tlmpprogram___v0::setproginfo ( const char *name, const char *version, const char *desc) { priv->progname.setfrom (name); priv->version.setfrom (version); priv->desc.setfrom (desc); } void _F_tlmpprogram___v0::setproginfo ( const char *name, int version, int release, const char *desc) { char tmp[20]; snprintf (tmp,sizeof(tmp)-1,"%d.%d",version,release); setproginfo (name,tmp,desc); } void _F_tlmpprogram___v0::setgrouparg (const char *desc) { priv->args.add (new TLMPARG(desc)); } void _F_tlmpprogram___v0::setarg ( const char letter, const char *name, const char *desc, const char *&val, bool mandatory) { priv->args.add (new TLMPARG(letter,name,desc,val,mandatory)); } void _F_tlmpprogram___v0::setarg ( const char letter, const char *name, const char *desc, SSTRING &val, bool mandatory) { priv->args.add (new TLMPARG(letter,name,desc,val,mandatory)); } void _F_tlmpprogram___v0::setarg ( const char letter, const char *name, const char *desc, SSTRINGS &vals, bool mandatory) { priv->args.add (new TLMPARG(letter,name,desc,vals,mandatory)); } void _F_tlmpprogram___v0::setarg ( const char letter, const char *name, const char *desc, int &val, bool mandatory) { priv->args.add (new TLMPARG(letter,name,desc,val,mandatory)); } void _F_tlmpprogram___v0::setarg ( const char letter, const char *name, const char *desc, bool &val, bool mandatory) { priv->args.add (new TLMPARG(letter,name,desc,val,mandatory)); } void _F_tlmpprogram___v1::usage() { FILE *fd = priv->usage_fd ; fprintf (fd,MSG_U(I_PROGUSAGE,"%s version %s\n\n%s\n") ,priv->progname.get(),priv->version.get() ,priv->desc.get()); fprintf (fd, "\n"); int maxlen = 0; for (int i=0; iargs.getnb(); i++){ TLMPARG *arg = priv->args.getitem(i); if (arg->type != TLMPARG::ARG_GROUP){ int len = strlen(arg->name); if (len > maxlen) maxlen = len; } } int fill = maxlen + 9; for (int i=0; iargs.getnb(); i++){ TLMPARG *arg = priv->args.getitem(i); if (arg->type == TLMPARG::ARG_GROUP){ fprintf (fd, "\n%s\n\n",arg->desc); }else{ if (isalpha(arg->letter)){ fprintf (fd, " -%c",arg->letter); }else{ fputs (" ",fd); } SSTRINGS lines; int nb = str_cnv2lines(arg->desc,lines); int len = fprintf (fd, " --%s ",arg->name); int start = 1; int fillone = fill - (len+4); if (arg->mandatory){ fprintf (fd, "%*s%s\n",fillone,"",MSG_U(I_MANDATORY,"(Mandatory)")); start = 0; }else{ fprintf (fd, "%*s%s\n",fillone,"",lines.getitem(0)->get()); } for (int j=start; jget()); } if (!arg->mandatory){ // Print the default value, using the value in the variable if (arg->defval.is_filled()){ fprintf (fd, "%*s%s: %s\n",fill,"",MSG_U(I_DEFVAL,"Default value") ,arg->defval.get()); } } } } if (first != NULL){ fprintf (fd, "\n"); fprintf (fd, " --help-other %s\n",MSG_U(I_HELPOTHER,"other/obscure/debug command line options")); } fprintf (fd, "\n"); } void _F_tlmpprogram___v1::showerror(const char *msg) { fprintf (stderr,"%s",msg); } /* No argument by default */ int _F_tlmpprogram___v1::onearg(const char *, const char *) { return -1; } /* Main called when there is no argument. the default call the usage function If a program may be called with and without argument, its main_noarg function just have to call main(0,NULL); */ int _F_tlmpprogram___v1::main_noarg() { usage(); return -1; } /* Main called when there is 1 or more arguments. the default call the usage function */ int _F_tlmpprogram___v1::main(int, char *[]) { usage(); return -1; } void _F_tlmpprogram___v1::init() { } static _F_tlmpprogram___v1 *ctx; static void tlmpprogram_error (const char *msg) { ctx->showerror (msg); } static int tlmpprogram_loadif ( const char *path, const char *lang, SSTRINGS &dir, const char *pkg) { int ret = -1; int nb = dir.getnb(); int len = strlen(pkg); for (int i=0; iget(); if (strncmp(pkg,f,len)==0 && (f[len] == '\0' || f[len] == '-')){ translat_load (path,"LINUXCONF_DICT",f,"LINUXCONF_LANG",lang); ret = 0; break; } } return ret; } static const char *tlmpprogram_getprog(char *argv[]) { const char *progname = strrchr(argv[0],'/'); if (progname == NULL){ progname = argv[0]; }else{ progname++; } return progname; } /* Check for short and long name option with argument or not. Check against the "setarg" argument and then call the onearg functag. */ static int tlmpprogram_checkarg ( _F_tlmpprogram___v1 &c, const TLMPARGS &args, const char *arg, const char *val) { int ret = -1; bool missing_arg = false; if (val == NULL || (val[0] == '-' && val[1] == '-')){ missing_arg = true; val = ""; } for (int i=0; itype != TLMPARG::ARG_GROUP && ((a->letter == arg[1] && arg[1] != '-') || (arg[1] == '-' && strcmp(a->name,arg+2)==0))){ if (a->type == TLMPARG::ARG_STRINGS){ if (!a->seen){ /* #Spec: tlmpprogram / SSTRINGS arguments We can set default values in SSTRINGS and the user is allowed to override them. The first time the option is seen, the SSTRINGS array is reset. */ a->valstrs->remove_all(); } a->valstrs->add (val); ret = 1; }else if (a->seen){ fprintf (stderr,"Option %s can't be repeated, ignored\n",arg); }else if (a->type == TLMPARG::ARG_PTSTR){ *a->valptstr = val; ret = 1; }else if (a->type == TLMPARG::ARG_BOOL){ *a->valbool = true; ret = 0; }else if (a->type == TLMPARG::ARG_INT){ if (!isdigit(val[0]) && val[0] != '-'){ fprintf (stderr,MSG_U(E_NOTNUM,"Option %s, invalid numeric argument: %s, Using value 0\n"),arg,val); *a->valint = 0; }else{ *a->valint = atoi(val); ret = 1; } }else if (a->type == TLMPARG::ARG_STRING){ a->valstr->setfrom(val); ret = 1; } a->seen = true; break; } } if (ret == -1){ ret = c.onearg (arg,val); } if (ret == 1 && missing_arg){ fprintf (stderr,MSG_U(E_MISSINGARG,"Missing value for option %s\n"),arg); ret = -1; } return ret; } static void tlmpprogram_setdbpath (const SSTRING &dbname, const SSTRING &progname) { const char *home = getenv ("HOME"); if (home != NULL){ SSTRING path; path.setfromf("%s/.tlmp",home); mkdir (path.get(),0700); // Make sure the sub-dir is created const char *name = dbname.get(); if (name[0] == '\0') name = progname.get(); path.setfromf("%s/.tlmp/%s.conf",home,name); linuxconf_setdbpath (path.get()); linuxconf_forget(); } } /* Check the TLMP_OPTIONs (other) Return -1 if none found. Return 0 if found or 1 if found and the value was used. */ static int tlmp_check_other(const char *optname, const char *val, int &errarg) { int ret = -1; TLMP_OPTION *pt = first; while (pt != NULL){ if (strcmp(pt->getname(),optname+2)==0){ if (pt->needval()){ if (pt->setval (val)==-1) errarg++; ret = 1; }else{ pt->setval (NULL); ret = 0; } break; } pt = pt->getnext(); } return ret; } // Return true if the option was specified on the command line bool _F_tlmpprogram___v1::opt_was_set(const char *optname) { bool ret = false; TLMPARGS *args = &priv->args; for (int i=0; isize(); i++){ TLMPARG *arg = args->getitem(i); if (strcmp(arg->name,optname)==0){ ret = arg->seen; break; } } return ret; } int tlmpprogram___v1 ( _F_tlmpprogram___v1 &c, int argc, char *argv[], const char *packages[]) { _F_tlmpprogram___v0_private priv; priv.usage_fd = stderr ; c.priv = &priv; priv.progname.setfrom (tlmpprogram_getprog (argv)); ctx = &c; diagui_seticonpath ("/usr/lib64/tlmp/images"); diagui_seticonpath ("/usr/lib/tlmp/images"); diagui_seticonpath ("/usr/share/icons"); diagui_seticonpath ("/usr/share/icons/mini"); diagui_seticonpath ("/usr/lib64/linuxconf/images"); diagui_seticonpath ("/usr/lib/linuxconf/images"); tlmp_seterrorfct (tlmpprogram_error); tlmpprogram_setdbpath (priv.dbname,priv.progname); const char *lang = linuxconf_getlang(); linuxconf_loadlibmsg ("/usr/lib/tlmp"); // translat_load ("/usr/lib/tlmp/help","tlmp", lang); // Load the various dictionary files // Assumes all dictionnary are located in /usr/lib/tlmp/help.lang // or in the linuxconf project SSTRINGS tbtlmp,tblinuxconf; dir_getlist ("/usr/lib/tlmp/help.eng",".eng",tbtlmp); dir_getlist ("/usr/lib/linuxconf/help.eng",".eng",tblinuxconf); for (int i=0; packages[i] != NULL; i++){ const char *pkg = packages[i]; if (tlmpprogram_loadif ("/usr/lib/tlmp/help",lang,tbtlmp,pkg)==-1){ tlmpprogram_loadif ("/usr/lib/linuxconf/help",lang,tblinuxconf,pkg); } } translat_checkmissing(); c.init(); tlmpprogram_setdbpath (priv.dbname,priv.progname); int i; int errarg = 0; argc = dialog_parseuioptions(argc,argv); bool help_requested = false; for (i=1; imandatory && !pta->seen){ errarg++; if (argc > 1){ // We only complain about mandatory option // if there were some argument passed. If no // argument, we simply show the help fprintf (stderr,MSG_U(E_NOTSPECIFIED,"Option %s is mandatory\n") ,pta->name); } } } if (errarg > 0){ c.usage(); }else if (argc == i){ ret = c.main_noarg(); }else{ ret = c.main (argc-i,argv+i); } } tlmp_seterrorfct (NULL); return ret; } int tlmpprogram___v1 ( _F_tlmpprogram___v1 &c, int argc, char *argv[]) { static const char *packages[]={NULL}; return tlmpprogram___v1 (c,argc,argv,packages); } int tlmpprogram___v1 ( _F_tlmpprogram___v1 &c, int argc, char *argv[], const char *package) { static const char *packages[]={package,NULL}; return tlmpprogram___v1 (c,argc,argv,packages); }