From b89456a346e176c4dc536e7de8f14b152cb2b15b Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 21 Dec 2004 11:32:13 +0000 Subject: widget: redefine, version control, better kb svn path=/trunk/externals/miXed/; revision=2425 --- toxy/build_counter | 4 +- toxy/widget.c | 160 ++++++++++++++++++++++++++++++++++++++++++------ toxy/widgettype.c | 177 ++++++++++++++++++++++++++++------------------------- toxy/widgettype.h | 5 +- 4 files changed, 241 insertions(+), 105 deletions(-) (limited to 'toxy') diff --git a/toxy/build_counter b/toxy/build_counter index 601f7ac..3be6b67 100644 --- a/toxy/build_counter +++ b/toxy/build_counter @@ -1,7 +1,7 @@ #define TOXY_VERSION "0.1" #define TOXY_RELEASE "alpha" -#define TOXY_BUILD 13 +#define TOXY_BUILD 14 #if 0 -TOXY_SNAPSHOT = 0.1-alpha13 +TOXY_SNAPSHOT = 0.1-alpha14 #endif diff --git a/toxy/widget.c b/toxy/widget.c index 8daa588..b0b83ac 100644 --- a/toxy/widget.c +++ b/toxy/widget.c @@ -23,6 +23,7 @@ static t_class *makeshift_class; #ifdef KRZYSZCZ //#define WIDGET_DEBUG //#define TOW_DEBUG +//#define WIDGET_PROFILE #endif enum { WIDGET_NOVIS = 0, WIDGET_PUSHVIS, WIDGET_REVIS }; @@ -93,7 +94,6 @@ typedef struct _tow t_symbol *x_cvname; t_symbol *x_type; /* 2nd creation arg: widget's type */ t_symbol *x_name; /* 3rd creation arg: widget's name */ - t_widgettype *x_typedef; t_widgetentry *x_widgetlist; struct _tow *x_next; /* next in the global towlist */ } t_tow; @@ -113,6 +113,69 @@ static t_symbol *widgetps_atsymbol; static t_symbol *widgetps_atstore; static t_symbol *widgetps_atrestore; +#ifdef WIDGET_PROFILE +static double widgetprofile_lasttime; + +static double widgetprofile_step(void) +{ + double newtime = sys_getrealtime(), + delta = newtime - widgetprofile_lasttime; + widgetprofile_lasttime = newtime; + return (delta); +} + +static int widgetprofile_handlerphase = 0; +static double widgetprofile_handlerslice[3]; +static double widgetprofile_handlerdelta[2]; + +static void widgetprofile_handler_enter(void) +{ + widgetprofile_handlerphase = 1; + widgetprofile_step(); +} + +static void widgetprofile_handler_eval(void) +{ + widgetprofile_handlerphase = 2; + widgetprofile_handlerdelta[0] = widgetprofile_step(); +} + +static void widgetprofile_handler_push(void) +{ + widgetprofile_handlerphase = 3; + widgetprofile_handlerdelta[1] = widgetprofile_step(); +} + +static void widgetprofile_handler_quit(void) +{ + if (widgetprofile_handlerphase == 3) + { + widgetprofile_handlerslice[2] += widgetprofile_step(); + widgetprofile_handlerslice[0] += widgetprofile_handlerdelta[0]; + widgetprofile_handlerslice[1] += widgetprofile_handlerdelta[1]; + } + widgetprofile_handlerphase = 0; +} + +static void widget_profile(t_widget *x) +{ + fputs("total time in ms:\n", stderr); + fprintf(stderr, "handler get %g\n", widgetprofile_handlerslice[0] * 1000.); + fprintf(stderr, "handler eval %g\n", widgetprofile_handlerslice[1] * 1000.); + fprintf(stderr, "handler push %g\n", widgetprofile_handlerslice[2] * 1000.); +} + +#define WIDGETPROFILE_HANDLER_ENTER widgetprofile_handler_enter() +#define WIDGETPROFILE_HANDLER_EVAL widgetprofile_handler_eval() +#define WIDGETPROFILE_HANDLER_PUSH widgetprofile_handler_push() +#define WIDGETPROFILE_HANDLER_QUIT widgetprofile_handler_quit() +#else +#define WIDGETPROFILE_HANDLER_ENTER +#define WIDGETPROFILE_HANDLER_EVAL +#define WIDGETPROFILE_HANDLER_PUSH +#define WIDGETPROFILE_HANDLER_QUIT +#endif + static char *widget_propsresolver(t_pd *owner, int ac, t_atom *av) { t_widget *x = (t_widget *)owner; @@ -222,6 +285,9 @@ static void widget_transtick(t_widget *x) newt->te_binbuf = bb; newt->te_xpix = oldt->te_xpix; newt->te_ypix = oldt->te_ypix; + outlet_new(newt, &s_); + inlet_new(newt, &newt->ob_pd, &s_, &s_); + /* FIXME preserve connections */ glist_add(x->x_glist, &newt->te_g); if (glist_isvisible(x->x_glist)) { @@ -322,10 +388,6 @@ static void widget_pushoptions(t_widget *x, int doit) static void widget_pushinits(t_widget *x) { - if (masterwidget_ievaluate(x->x_transient, 0, 0, 0, x->x_arguments)) - scriptlet_vpush(x->x_transient, "masterinit"); - else - bug("widget_pushinits (master)"); if (widgettype_isdefined(x->x_typedef)) { int sz; @@ -584,6 +646,7 @@ static void widget_anything(t_widget *x, t_symbol *s, int ac, t_atom *av) t_atom *hp; t_symbol *sel; char buf[MAXPDSTRING]; + WIDGETPROFILE_HANDLER_ENTER; buf[0] = '@'; strcpy(buf + 1, s->s_name); sel = gensym(buf); @@ -592,13 +655,18 @@ static void widget_anything(t_widget *x, t_symbol *s, int ac, t_atom *av) sel, &hlen))) && hlen > 1) { + WIDGETPROFILE_HANDLER_EVAL; scriptlet_reset(x->x_auxscript); scriptlet_add(x->x_auxscript, 0, 0, hlen - 1, hp + 1); if (scriptlet_evaluate(x->x_auxscript, x->x_transient, 1, ac, av, x->x_arguments)) + { + WIDGETPROFILE_HANDLER_PUSH; scriptlet_push(x->x_transient); + } } else loud_nomethod((t_pd *)x, s); + WIDGETPROFILE_HANDLER_QUIT; } } } @@ -608,17 +676,21 @@ static void widget_bang(t_widget *x) { int ac; t_atom *av; + WIDGETPROFILE_HANDLER_ENTER; if ((av = props_getone(x->x_handlers, widgetps_atbang, &ac)) || (av = props_getone(widgettype_gethandlers(x->x_typedef), widgetps_atbang, &ac))) { if (ac > 1) { + WIDGETPROFILE_HANDLER_EVAL; scriptlet_reset(x->x_transient); scriptlet_add(x->x_transient, 1, 1, ac - 1, av + 1); + WIDGETPROFILE_HANDLER_PUSH; scriptlet_push(x->x_transient); } } + WIDGETPROFILE_HANDLER_QUIT; } /* LATER cache this */ @@ -626,6 +698,7 @@ static void widget_float(t_widget *x, t_float f) { int ac; t_atom *av; + WIDGETPROFILE_HANDLER_ENTER; if ((av = props_getone(x->x_handlers, widgetps_atfloat, &ac)) || (av = props_getone(widgettype_gethandlers(x->x_typedef), widgetps_atfloat, &ac))) @@ -633,14 +706,19 @@ static void widget_float(t_widget *x, t_float f) if (ac > 1) { t_atom at; + WIDGETPROFILE_HANDLER_EVAL; SETFLOAT(&at, f); scriptlet_reset(x->x_auxscript); scriptlet_add(x->x_auxscript, 0, 0, ac - 1, av + 1); if (scriptlet_evaluate(x->x_auxscript, x->x_transient, 1, 1, &at, x->x_arguments)) + { + WIDGETPROFILE_HANDLER_PUSH; scriptlet_push(x->x_transient); + } } } + WIDGETPROFILE_HANDLER_QUIT; } /* LATER cache this */ @@ -648,6 +726,7 @@ static void widget_symbol(t_widget *x, t_symbol *s) { int ac; t_atom *av; + WIDGETPROFILE_HANDLER_ENTER; if ((av = props_getone(x->x_handlers, widgetps_atsymbol, &ac)) || (av = props_getone(widgettype_gethandlers(x->x_typedef), widgetps_atsymbol, &ac))) @@ -655,14 +734,19 @@ static void widget_symbol(t_widget *x, t_symbol *s) if (ac > 1) { t_atom at; + WIDGETPROFILE_HANDLER_EVAL; SETSYMBOL(&at, s); scriptlet_reset(x->x_auxscript); scriptlet_add(x->x_auxscript, 0, 0, ac - 1, av + 1); if (scriptlet_evaluate(x->x_auxscript, x->x_transient, 1, 1, &at, x->x_arguments)) + { + WIDGETPROFILE_HANDLER_PUSH; scriptlet_push(x->x_transient); + } } } + WIDGETPROFILE_HANDLER_QUIT; } static void widget_store(t_widget *x, t_symbol *s) @@ -754,6 +838,30 @@ static void widget_refresh(t_widget *x) widget_update(x, x->x_arguments); } +static int widget_resettype(t_widget *x, t_widgettype *wt) +{ + if (wt == x->x_typedef) + { + if (!(x->x_tkclass = widgettype_tkclass(x->x_typedef))) + x->x_tkclass = x->x_type; + props_clone(x->x_arguments, widgettype_getarguments(x->x_typedef)); + /* FIXME widget_addmessage(x, 0, ac, av); */ + widget_pushconstructors(x); + widget_refresh(x); + return (1); + } + else + { + bug("widget_resettype"); + return (0); + } +} + +static void widget_redefine(t_widget *x) +{ + widget_resettype(x, widgettype_reload(x->x_type)); +} + static void widget__failure(t_widget *x, t_symbol *s, int ac, t_atom *av) { #if 0 @@ -937,9 +1045,6 @@ static void widget_debug(t_widget *x) bp = widgettype_getdestructor(x->x_typedef, &sz); fprintf(stderr, "type destructor (size %d):\n\"%s\"\n", sz, (bp ? bp : bempty)); - bp = masterwidget_getinitializer(&sz); - fprintf(stderr, "master initializer (size %d):\n\"%s\"\n", - sz, (bp ? bp : bempty)); bp = widgettype_getinitializer(x->x_typedef, &sz); fprintf(stderr, "type initializer (size %d):\n\"%s\"\n", sz, (bp ? bp : bempty)); @@ -982,32 +1087,33 @@ static void widget_free(t_widget *x) static void *widget_new(t_symbol *s, int ac, t_atom *av) { t_widget *x; + t_symbol *type = 0, *name = 0; char buf[MAXPDSTRING]; if (widget_transforming) return (0); masterwidget_validate(); - x = (t_widget *)pd_new(widget_class); - x->x_type = 0; - x->x_name = 0; if (ac && av->a_type == A_SYMBOL) { - x->x_type = av->a_w.w_symbol; + type = av->a_w.w_symbol; ac--; av++; } if (ac && av->a_type == A_SYMBOL) { - x->x_name = av->a_w.w_symbol; + name = av->a_w.w_symbol; ac--; av++; } /* LATER think about anonymous widgets (single arg, or '.') */ - if (!x->x_type || x->x_type == &s_ || - !x->x_name || x->x_name == &s_) + if (!type || type == &s_ || !name || name == &s_) { - loud_error((t_pd *)x, "bad arguments for a widget"); - loud_errand((t_pd *)x, - "expecting \"widget [properties]\""); + loud_error(0, "bad arguments for a widget"); + loud_errand(0, "expecting \"widget [properties]\""); return (0); } + + x = (t_widget *)pd_new(widget_class); + x->x_type = type; + x->x_name = name; + sprintf(buf, "%s%x", x->x_name->s_name, (int)x); pd_bind((t_pd *)x, x->x_cbtarget = gensym(buf)); sprintf(buf, "%s%x.rp", x->x_name->s_name, (int)x); @@ -1098,6 +1204,15 @@ static void tow_anything(t_tow *x, t_symbol *s, int ac, t_atom *av) typedmess((t_pd *)we->we_widget, s, ac, av); } +static void tow_redefine(t_tow *x) +{ + t_widgettype *wt = widgettype_reload(x->x_type); + t_widgetentry *we; + for (we = x->x_widgetlist; we; we = we->we_next) + if (!widget_resettype(we->we_widget, wt)) + break; +} + static void tow__callback(t_tow *x, t_symbol *s, int ac, t_atom *av) { if (ac == 1) @@ -1362,6 +1477,8 @@ void widget_setup(void) gensym("tot"), A_GIMME, 0); class_addmethod(widget_class, (t_method)widget_refresh, gensym("refresh"), 0); + class_addmethod(widget_class, (t_method)widget_redefine, + gensym("redefine"), 0); class_addmethod(widget_class, (t_method)widget__failure, gensym("_failure"), A_GIMME, 0); class_addmethod(widget_class, (t_method)widget__config, @@ -1380,11 +1497,16 @@ void widget_setup(void) #ifdef WIDGET_DEBUG class_addmethod(widget_class, (t_method)widget_debug, gensym("debug"), 0); +#endif +#ifdef WIDGET_PROFILE + class_addmethod(widget_class, (t_method)widget_profile, + gensym("profile"), 0); #endif hammerfile_setup(widget_class, 0); makeshift_class = class_new(gensym("text"), 0, 0, sizeof(t_text), + /* inlet added explicitly (cf text_class) */ CLASS_NOINLET | CLASS_PATCHABLE, 0); tow_class = class_new(gensym("tow"), @@ -1395,6 +1517,8 @@ void widget_setup(void) class_addfloat(tow_class, tow_float); class_addsymbol(tow_class, tow_symbol); class_addanything(tow_class, tow_anything); + class_addmethod(tow_class, (t_method)tow_redefine, + gensym("redefine"), 0); class_addmethod(tow_class, (t_method)tow__callback, gensym("_cb"), A_GIMME, 0); #ifdef TOW_DEBUG diff --git a/toxy/widgettype.c b/toxy/widgettype.c index 408ba4a..20ff933 100644 --- a/toxy/widgettype.c +++ b/toxy/widgettype.c @@ -37,7 +37,6 @@ struct _masterwidget t_symbol *mw_target; t_scriptlet *mw_setupscript; t_dict *mw_typemap; - t_widgettype *mw_mastertype; /* contains master initializer */ t_widgettype *mw_parsedtype; /* the type currently parsed, if loading */ t_binbuf *mw_bb; /* auxiliary, LATER remove */ }; @@ -58,6 +57,21 @@ static void widgettype_map(t_widgettype *wt, char *cls, char *pkg) wt->wt_tkpackage = (pkg ? gensym(pkg) : 0); } +#if 0 +/* only for debugging (never call, unless certain that nobody references wt) */ +static void widgettype_free(t_masterwidget *mw, t_widgettype *wt) +{ + fprintf(stderr, "widgettype free... "); + dict_unbind(mw->mw_typemap, (t_pd *)wt, wt->wt_typekey); + props_freeall(wt->wt_options); + scriptlet_free(wt->wt_iniscript); + scriptlet_free(wt->wt_newscript); + scriptlet_free(wt->wt_freescript); + pd_free((t_pd *)wt); + fprintf(stderr, "done\n"); +} +#endif + static t_widgettype *widgettype_new(t_masterwidget *mw, char *typ, char *cls, char *pkg) { @@ -101,20 +115,12 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *caller, char *rc, typeval = (t_widgettype *)dict_firstvalue(mw->mw_typemap, typekey, 0); if (caller == (t_pd *)mw) { /* setup.wid or built-in defaults */ - if (mw->mw_mastertype) - { /* no master type in setup.wid, extracting built-in one */ - if (typeval != mw->mw_mastertype) - return (SCRIPTLET_LOCK); - } - else + if (typeval) { - if (typeval) - { - /* LATER rethink */ - loud_warning((t_pd *)mw, 0, "redefinition of '%s'\ + /* LATER rethink */ + loud_warning((t_pd *)mw, 0, "redefinition of '%s'\ in \"%s.wid\" file, ignored", buf, rc); - return (SCRIPTLET_LOCK); - } + return (SCRIPTLET_LOCK); } } else @@ -196,52 +202,71 @@ static t_scriptlet *masterwidget_cmnthook(t_pd *caller, char *rc, return (SCRIPTLET_UNLOCK); } -t_widgettype *widgettype_get(t_symbol *s) +static int widgettype_doload(t_widgettype *wt, t_symbol *s) { - t_widgettype *wt; - /* Design decision: setup.wid defs are NOT overridden by .wid - (sacrificing flexibility for feature stability). */ - if (wt = (t_widgettype *)dict_firstvalue(masterwidget->mw_typemap, - dict_key(masterwidget->mw_typemap, - s->s_name), 0)) - masterwidget->mw_parsedtype = 0; - else - { - /* first instance of a type not defined in setup.wid */ - wt = widgettype_new(masterwidget, s->s_name, 0, 0); - masterwidget->mw_parsedtype = wt; - } - if (masterwidget->mw_parsedtype) + int result = 0; + /* .wid searched in the current patch's dir + pd_path, + but not in `pwd` */ + t_scriptlet *mwsp = + scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, + masterwidget->mw_target, 0, canvas_getcurrent(), 0); + masterwidget->mw_parsedtype = wt; + + if (scriptlet_rcload(mwsp, (t_pd *)wt, + s->s_name, ".wid", 0, masterwidget_cmnthook) + == SCRIPTLET_OK) { - /* .wid searched in the current patch's dir + pd_path, - but not in `pwd` */ - t_scriptlet *mwsp = - scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, - masterwidget->mw_target, 0, - canvas_getcurrent(), 0); - if (scriptlet_rcload(mwsp, (t_pd *)wt, - s->s_name, ".wid", 0, masterwidget_cmnthook) - == SCRIPTLET_OK) - { #ifdef WIDGETTYPE_VERBOSE - post("using a separate %s's definition file", s->s_name); + post("using a separate %s's definition file", s->s_name); #endif - if (!scriptlet_isempty(mwsp)) + if (!scriptlet_isempty(mwsp)) + { + t_scriptlet *sp = + scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, + masterwidget->mw_target, 0, 0, 0); + if (scriptlet_evaluate(mwsp, sp, 0, 0, 0, 0)) { - t_scriptlet *sp = - scriptlet_new((t_pd *)masterwidget, masterwidget->mw_target, - masterwidget->mw_target, 0, 0, 0); - if (scriptlet_evaluate(mwsp, sp, 0, 0, 0, 0)) - { - scriptlet_push(sp); - scriptlet_append(masterwidget->mw_setupscript, mwsp); - } - else bug("widgettype_get"); - scriptlet_free(sp); + scriptlet_push(sp); + scriptlet_append(masterwidget->mw_setupscript, mwsp); } + else bug("widgettype_doload"); + scriptlet_free(sp); } - scriptlet_free(mwsp); + result = 1; } + scriptlet_free(mwsp); + return (result); +} + +t_widgettype *widgettype_find(t_symbol *s) +{ + return ((t_widgettype *)dict_firstvalue(masterwidget->mw_typemap, + dict_key(masterwidget->mw_typemap, + s->s_name), 0)); +} + +t_widgettype *widgettype_get(t_symbol *s) +{ + t_widgettype *wt = widgettype_find(s); + /* Design decision: default widget definitions are NOT implicitly + overridden by .wid (sacrificing flexibility for feature + stability). */ + if (!wt) + { + /* first instance of a type not defined in setup.wid */ + wt = widgettype_new(masterwidget, s->s_name, 0, 0); + widgettype_doload(wt, s); + } + return (wt); +} + +t_widgettype *widgettype_reload(t_symbol *s) +{ + t_widgettype *wt = widgettype_find(s); + if (!wt) + /* first instance of a type not defined in setup.wid */ + wt = widgettype_new(masterwidget, s->s_name, 0, 0); + widgettype_doload(wt, s); return (wt); } @@ -319,29 +344,14 @@ void widgettype_setup(void) } } -char *masterwidget_getinitializer(int *szp) -{ - return (scriptlet_getcontents(masterwidget->mw_mastertype->wt_iniscript, - szp)); -} - char *masterwidget_getcontents(int *szp) { return (scriptlet_getcontents(masterwidget->mw_setupscript, szp)); } -int masterwidget_ievaluate(t_scriptlet *outsp, int visedonly, - int ac, t_atom *av, t_props *argprops) -{ - return (scriptlet_evaluate(masterwidget->mw_mastertype->wt_iniscript, - outsp, visedonly, ac, av, argprops)); -} - void masterwidget_validate(void) { int rcresult; - t_symbol *typekey; - t_widgettype *typeval; char buf[MAXPDSTRING]; if (masterwidget) return; @@ -359,7 +369,6 @@ void masterwidget_validate(void) masterwidget->mw_target, 0, 0, 0); masterwidget->mw_bb = binbuf_new(); masterwidget->mw_parsedtype = 0; - masterwidget->mw_mastertype = 0; rcresult = scriptlet_rcload(masterwidget->mw_setupscript, 0, "setup", ".wid", @@ -372,24 +381,28 @@ void masterwidget_validate(void) } else { + char *msg; + if (rcresult == SCRIPTLET_NOFILE) + msg = "no"; + else if (rcresult == SCRIPTLET_BADFILE) + msg = "corrupt"; + else if (rcresult == SCRIPTLET_NOVERSION) + msg = "unknown version of"; + else if (rcresult == SCRIPTLET_OLDERVERSION) + msg = "obsolete"; + else if (rcresult == SCRIPTLET_NEWERVERSION) + msg = "incompatible"; + else + msg = "cannot use"; loud_warning((t_pd *)masterwidget, 0, - "no file 'setup.wid'... using built-in defaults"); + "%s file 'setup.wid'... using built-in defaults", msg); } - typekey = dict_key(masterwidget->mw_typemap, "master"); - if ((typeval = (t_widgettype *)dict_firstvalue(masterwidget->mw_typemap, - typekey, 0)) - && !scriptlet_isempty(masterwidget->mw_setupscript)) - { - masterwidget->mw_mastertype = typeval; + if (!scriptlet_isempty(masterwidget->mw_setupscript)) rcresult = SCRIPTLET_OK; - } else if (rcresult == SCRIPTLET_OK) { - /* LATER think about adding only missing part to existing local defs */ - loud_warning((t_pd *)masterwidget, 0, "%s missing in file 'setup.wid'", - (typeval ? "setup definitions" : "master initializer")); - masterwidget->mw_mastertype = - widgettype_new(masterwidget, "master", 0, 0); + loud_warning((t_pd *)masterwidget, 0, + "missing setup definitions in file 'setup.wid'"); scriptlet_reset(masterwidget->mw_setupscript); rcresult = scriptlet_rcparse(masterwidget->mw_setupscript, 0, "master", @@ -397,7 +410,7 @@ void masterwidget_validate(void) } else { - bug("masterwidget_initialize 1"); + bug("masterwidget_validate 1"); rcresult = SCRIPTLET_BADFILE; } if (rcresult == SCRIPTLET_OK) @@ -408,7 +421,7 @@ void masterwidget_validate(void) if (scriptlet_evaluate(masterwidget->mw_setupscript, sp, 0, 0, 0, 0)) scriptlet_push(sp); else - bug("masterwidget_initialize 2"); + bug("masterwidget_validate 2"); scriptlet_free(sp); } } diff --git a/toxy/widgettype.h b/toxy/widgettype.h index d2d9858..a35f114 100644 --- a/toxy/widgettype.h +++ b/toxy/widgettype.h @@ -15,7 +15,9 @@ EXTERN_STRUCT _widgettype; EXTERN_STRUCT _masterwidget; #define t_masterwidget struct _masterwidget +t_widgettype *widgettype_find(t_symbol *s); t_widgettype *widgettype_get(t_symbol *s); +t_widgettype *widgettype_reload(t_symbol *s); int widgettype_isdefined(t_widgettype *wt); t_symbol *widgettype_tkclass(t_widgettype *wt); t_props *widgettype_getoptions(t_widgettype *wt); @@ -33,10 +35,7 @@ int widgettype_devaluate(t_widgettype *wt, t_scriptlet *outsp, int visedonly, int ac, t_atom *av, t_props *argprops); void widgettype_setup(void); -char *masterwidget_getinitializer(int *szp); char *masterwidget_getcontents(int *szp); -int masterwidget_ievaluate(t_scriptlet *outsp, int visedonly, - int ac, t_atom *av, t_props *argprops); void masterwidget_validate(void); #endif -- cgit v1.2.1