# HG changeset patch # User Bram Moolenaar # Date 1368623549 -7200 # Node ID cfd76908da252e03f46ea15cde44a3664e895fb0 # Parent 7324bd8b67b191bb4b24af1765703ca2754e045e updated for version 7.3.949 Problem: Python: no easy access to tabpages. Solution: Add vim.tabpages and vim.current.tabpage. (ZyX) diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt --- a/runtime/doc/if_pyth.txt +++ b/runtime/doc/if_pyth.txt @@ -223,6 +223,20 @@ vim.windows *python-windows* :py w in vim.windows # Membership test :py n = len(vim.windows) # Number of elements :py for w in vim.windows: # Sequential access +< Note: vim.windows object always accesses current tab page,. + |python-tabpage|.windows objects are bound to parent |python-tabpage| + object and always use windows from that tab page (or throw vim.error + in case tab page was deleted). You can keep a reference to both + without keeping a reference to vim module object or |python-tabpage|, + they will not loose their properties in this case. + +vim.tabpages *python-tabpages* + A sequence object providing access to the list of vim tab pages. The + object supports the following operations: > + :py t = vim.tabpages[i] # Indexing (read-only) + :py t in vim.tabpages # Membership test + :py n = len(vim.tabpages) # Number of elements + :py for t in vim.tabpages: # Sequential access < vim.current *python-current* An object providing access (via specific attributes) to various @@ -230,6 +244,7 @@ vim.current *python-current* vim.current.line The current line (RW) String vim.current.buffer The current buffer (RO) Buffer vim.current.window The current window (RO) Window + vim.current.tabpage The current tab page (RO) TabPage vim.current.range The current line range (RO) Range The last case deserves a little explanation. When the :python or @@ -375,6 +390,8 @@ 5. Window objects *python-window* Window objects represent vim windows. You can obtain them in a number of ways: - via vim.current.window (|python-current|) - from indexing vim.windows (|python-windows|) + - from indexing "windows" attribute of a tab page (|python-tabpage|) + - from the "window" attribute of a tab page (|python-tabpage|) You can manipulate window objects only through their attributes. They have no methods, and no sequence or other interface. @@ -407,6 +424,24 @@ The height attribute is writable only if The width attribute is writable only if the screen is split vertically. ============================================================================== +6. Tab page objects *python-tabpage* + +Tab page objects represent vim tab pages. You can obtain them in a number of +ways: + - via vim.current.tabpage (|python-current|) + - from indexing vim.tabpages (|python-tabpages|) + +You can use this object to access tab page windows. They have no methods and +no sequence or other interfaces. + +Tab page attributes are: + number The tab page number like the one returned by + |tabpagenr()|. + windows Like |python-windows|, but for current tab page. + vars The tab page |t:| variables. + window Current tabpage window. + +============================================================================== 6. pyeval() and py3eval() Vim functions *python-pyeval* To facilitate bi-directional interface, you can use |pyeval()| and |py3eval()| diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -27,6 +27,7 @@ typedef int Py_ssize_t; /* Python 2.4 a #define INVALID_BUFFER_VALUE ((buf_T *)(-1)) #define INVALID_WINDOW_VALUE ((win_T *)(-1)) +#define INVALID_TABPAGE_VALUE ((tabpage_T *)(-1)) static int ConvertFromPyObject(PyObject *, typval_T *); static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *); @@ -1579,6 +1580,155 @@ static PyMappingMethods OptionsAsMapping (objobjargproc) OptionsAssItem, }; +/* Tabpage object + */ + +typedef struct +{ + PyObject_HEAD + tabpage_T *tab; +} TabPageObject; + +static PyObject *WinListNew(TabPageObject *tabObject); + +static PyTypeObject TabPageType; + + static int +CheckTabPage(TabPageObject *this) +{ + if (this->tab == INVALID_TABPAGE_VALUE) + { + PyErr_SetVim(_("attempt to refer to deleted tab page")); + return -1; + } + + return 0; +} + + static PyObject * +TabPageNew(tabpage_T *tab) +{ + TabPageObject *self; + + if (TAB_PYTHON_REF(tab)) + { + self = TAB_PYTHON_REF(tab); + Py_INCREF(self); + } + else + { + self = PyObject_NEW(TabPageObject, &TabPageType); + if (self == NULL) + return NULL; + self->tab = tab; + TAB_PYTHON_REF(tab) = self; + } + + return (PyObject *)(self); +} + + static void +TabPageDestructor(PyObject *self) +{ + TabPageObject *this = (TabPageObject *)(self); + + if (this->tab && this->tab != INVALID_TABPAGE_VALUE) + TAB_PYTHON_REF(this->tab) = NULL; + + DESTRUCTOR_FINISH(self); +} + + static PyObject * +TabPageAttr(TabPageObject *this, char *name) +{ + if (strcmp(name, "windows") == 0) + return WinListNew(this); + else if (strcmp(name, "number") == 0) + return PyLong_FromLong((long) get_tab_number(this->tab)); + else if (strcmp(name, "vars") == 0) + return DictionaryNew(this->tab->tp_vars); + else if (strcmp(name, "window") == 0) + { + /* For current tab window.c does not bother to set or update tp_curwin + */ + if (this->tab == curtab) + return WindowNew(curwin); + else + return WindowNew(this->tab->tp_curwin); + } + return NULL; +} + + static PyObject * +TabPageRepr(PyObject *self) +{ + static char repr[100]; + TabPageObject *this = (TabPageObject *)(self); + + if (this->tab == INVALID_TABPAGE_VALUE) + { + vim_snprintf(repr, 100, _(""), (self)); + return PyString_FromString(repr); + } + else + { + int t = get_tab_number(this->tab); + + if (t == 0) + vim_snprintf(repr, 100, _(""), + (self)); + else + vim_snprintf(repr, 100, _(""), t - 1); + + return PyString_FromString(repr); + } +} + +static struct PyMethodDef TabPageMethods[] = { + /* name, function, calling, documentation */ + { NULL, NULL, 0, NULL } +}; + +/* + * Window list object + */ + +static PyTypeObject TabListType; +static PySequenceMethods TabListAsSeq; + +typedef struct +{ + PyObject_HEAD +} TabListObject; + + static PyInt +TabListLength(PyObject *self UNUSED) +{ + tabpage_T *tp = first_tabpage; + PyInt n = 0; + + while (tp != NULL) + { + ++n; + tp = tp->tp_next; + } + + return n; +} + + static PyObject * +TabListItem(PyObject *self UNUSED, PyInt n) +{ + tabpage_T *tp; + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, --n) + if (n == 0) + return TabPageNew(tp); + + PyErr_SetString(PyExc_IndexError, _("no such tab page")); + return NULL; +} + /* Window object */ @@ -1588,8 +1738,6 @@ typedef struct win_T *win; } WindowObject; -static int WindowSetattr(PyObject *, char *, PyObject *); -static PyObject *WindowRepr(PyObject *); static PyTypeObject WindowType; static int @@ -1681,7 +1829,7 @@ WindowAttr(WindowObject *this, char *nam return OptionsNew(SREQ_WIN, this->win, (checkfun) CheckWindow, (PyObject *) this); else if (strcmp(name, "number") == 0) - return PyLong_FromLong((long) get_win_number(this->win)); + return PyLong_FromLong((long) get_win_number(this->win, firstwin)); else if (strcmp(name,"__members__") == 0) return Py_BuildValue("[ssssssss]", "buffer", "cursor", "height", "vars", "options", "number", "row", "col"); @@ -1797,7 +1945,7 @@ WindowRepr(PyObject *self) } else { - int w = get_win_number(this->win); + int w = get_win_number(this->win, firstwin); if (w == 0) vim_snprintf(repr, 100, _(""), @@ -1824,14 +1972,59 @@ static PySequenceMethods WinListAsSeq; typedef struct { PyObject_HEAD + TabPageObject *tabObject; } WinListObject; + static PyObject * +WinListNew(TabPageObject *tabObject) +{ + WinListObject *self; + + self = PyObject_NEW(WinListObject, &WinListType); + self->tabObject = tabObject; + Py_INCREF(tabObject); + + return (PyObject *)(self); +} + + static void +WinListDestructor(PyObject *self) +{ + TabPageObject *tabObject = ((WinListObject *)(self))->tabObject; + + if (tabObject) + Py_DECREF((PyObject *)(tabObject)); + + DESTRUCTOR_FINISH(self); +} + + static win_T * +get_firstwin(WinListObject *this) +{ + if (this->tabObject) + { + if (CheckTabPage(this->tabObject)) + return NULL; + /* For current tab window.c does not bother to set or update tp_firstwin + */ + else if (this->tabObject->tab == curtab) + return firstwin; + else + return this->tabObject->tab->tp_firstwin; + } + else + return firstwin; +} + static PyInt -WinListLength(PyObject *self UNUSED) +WinListLength(PyObject *self) { - win_T *w = firstwin; + win_T *w; PyInt n = 0; + if (!(w = get_firstwin((WinListObject *)(self)))) + return -1; + while (w != NULL) { ++n; @@ -1842,11 +2035,14 @@ WinListLength(PyObject *self UNUSED) } static PyObject * -WinListItem(PyObject *self UNUSED, PyInt n) +WinListItem(PyObject *self, PyInt n) { win_T *w; - for (w = firstwin; w != NULL; w = W_NEXT(w), --n) + if (!(w = get_firstwin((WinListObject *)(self)))) + return NULL; + + for (; w != NULL; w = W_NEXT(w), --n) if (n == 0) return WindowNew(w); @@ -3018,12 +3214,15 @@ CurrentGetattr(PyObject *self UNUSED, ch return (PyObject *)BufferNew(curbuf); else if (strcmp(name, "window") == 0) return (PyObject *)WindowNew(curwin); + else if (strcmp(name, "tabpage") == 0) + return (PyObject *)TabPageNew(curtab); else if (strcmp(name, "line") == 0) return GetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum); else if (strcmp(name, "range") == 0) return RangeNew(curbuf, RangeStart, RangeEnd); else if (strcmp(name,"__members__") == 0) - return Py_BuildValue("[ssss]", "buffer", "window", "line", "range"); + return Py_BuildValue("[sssss]", "buffer", "window", "line", "range", + "tabpage"); else { PyErr_SetString(PyExc_AttributeError, name); @@ -3568,6 +3767,23 @@ init_structs(void) WindowType.tp_setattr = WindowSetattr; #endif + vim_memset(&TabPageType, 0, sizeof(TabPageType)); + TabPageType.tp_name = "vim.tabpage"; + TabPageType.tp_basicsize = sizeof(TabPageObject); + TabPageType.tp_dealloc = TabPageDestructor; + TabPageType.tp_repr = TabPageRepr; + TabPageType.tp_flags = Py_TPFLAGS_DEFAULT; + TabPageType.tp_doc = "vim tab page object"; + TabPageType.tp_methods = TabPageMethods; +#if PY_MAJOR_VERSION >= 3 + TabPageType.tp_getattro = TabPageGetattro; + TabPageType.tp_alloc = call_PyType_GenericAlloc; + TabPageType.tp_new = call_PyType_GenericNew; + TabPageType.tp_free = call_PyObject_Free; +#else + TabPageType.tp_getattr = TabPageGetattr; +#endif + vim_memset(&BufMapType, 0, sizeof(BufMapType)); BufMapType.tp_name = "vim.bufferlist"; BufMapType.tp_basicsize = sizeof(BufMapObject); @@ -3582,6 +3798,14 @@ init_structs(void) WinListType.tp_as_sequence = &WinListAsSeq; WinListType.tp_flags = Py_TPFLAGS_DEFAULT; WinListType.tp_doc = "vim window list"; + WinListType.tp_dealloc = WinListDestructor; + + vim_memset(&TabListType, 0, sizeof(TabListType)); + TabListType.tp_name = "vim.tabpagelist"; + TabListType.tp_basicsize = sizeof(TabListType); + TabListType.tp_as_sequence = &TabListAsSeq; + TabListType.tp_flags = Py_TPFLAGS_DEFAULT; + TabListType.tp_doc = "vim tab page list"; vim_memset(&RangeType, 0, sizeof(RangeType)); RangeType.tp_name = "vim.range"; diff --git a/src/if_python.c b/src/if_python.c --- a/src/if_python.c +++ b/src/if_python.c @@ -624,10 +624,12 @@ static int initialised = 0; #define WIN_PYTHON_REF(win) win->w_python_ref #define BUF_PYTHON_REF(buf) buf->b_python_ref +#define TAB_PYTHON_REF(tab) tab->tp_python_ref static PyObject *OutputGetattr(PyObject *, char *); static PyObject *BufferGetattr(PyObject *, char *); static PyObject *WindowGetattr(PyObject *, char *); +static PyObject *TabPageGetattr(PyObject *, char *); static PyObject *RangeGetattr(PyObject *, char *); static PyObject *DictionaryGetattr(PyObject *, char*); static PyObject *ListGetattr(PyObject *, char *); @@ -1137,6 +1139,24 @@ RangeAssSlice(PyObject *self, PyInt lo, &((RangeObject *)(self))->end); } +/* TabPage object - Implementation + */ + + static PyObject * +TabPageGetattr(PyObject *self, char *name) +{ + PyObject *r; + + if (CheckTabPage((TabPageObject *)(self))) + return NULL; + + r = TabPageAttr((TabPageObject *)(self), name); + if (r || PyErr_Occurred()) + return r; + else + return Py_FindMethod(TabPageMethods, self, name); +} + /* Window object - Implementation */ @@ -1155,6 +1175,24 @@ WindowGetattr(PyObject *self, char *name return Py_FindMethod(WindowMethods, self, name); } +/* Tab page list object - Definitions + */ + +static PySequenceMethods TabListAsSeq = { + (PyInquiry) TabListLength, /* sq_length, len(x) */ + (binaryfunc) 0, /* sq_concat, x+y */ + (PyIntArgFunc) 0, /* sq_repeat, x*n */ + (PyIntArgFunc) TabListItem, /* sq_item, x[i] */ + (PyIntIntArgFunc) 0, /* sq_slice, x[i:j] */ + (PyIntObjArgProc) 0, /* sq_ass_item, x[i]=v */ + (PyIntIntObjArgProc) 0, /* sq_ass_slice, x[i:j]=v */ + (objobjproc) 0, +#if PY_MAJOR_VERSION >= 2 + (binaryfunc) 0, + 0, +#endif +}; + /* Window list object - Definitions */ @@ -1198,6 +1236,17 @@ python_window_free(win_T *win) WIN_PYTHON_REF(win) = NULL; } } + + void +python_tabpage_free(tabpage_T *tab) +{ + if (TAB_PYTHON_REF(tab) != NULL) + { + TabPageObject *tp = TAB_PYTHON_REF(tab); + tp->tab = INVALID_TABPAGE_VALUE; + TAB_PYTHON_REF(tab) = NULL; + } +} #endif static BufMapObject TheBufferMap = @@ -1208,6 +1257,7 @@ static BufMapObject TheBufferMap = static WinListObject TheWindowList = { PyObject_HEAD_INIT(&WinListType) + NULL }; static CurrentObject TheCurrent = @@ -1215,6 +1265,11 @@ static CurrentObject TheCurrent = PyObject_HEAD_INIT(&CurrentType) }; +static TabListObject TheTabPageList = +{ + PyObject_HEAD_INIT(&TabListType) +}; + static int PythonMod_Init(void) { @@ -1229,8 +1284,10 @@ PythonMod_Init(void) PyType_Ready(&BufferType); PyType_Ready(&RangeType); PyType_Ready(&WindowType); + PyType_Ready(&TabPageType); PyType_Ready(&BufMapType); PyType_Ready(&WinListType); + PyType_Ready(&TabListType); PyType_Ready(&CurrentType); PyType_Ready(&OptionsType); @@ -1246,6 +1303,7 @@ PythonMod_Init(void) PyDict_SetItemString(dict, "buffers", (PyObject *)(void *)&TheBufferMap); PyDict_SetItemString(dict, "current", (PyObject *)(void *)&TheCurrent); PyDict_SetItemString(dict, "windows", (PyObject *)(void *)&TheWindowList); + PyDict_SetItemString(dict, "tabpages", (PyObject *)(void *)&TheTabPageList); tmp = DictionaryNew(&globvardict); PyDict_SetItemString(dict, "vars", tmp); Py_DECREF(tmp); diff --git a/src/if_python3.c b/src/if_python3.c --- a/src/if_python3.c +++ b/src/if_python3.c @@ -626,6 +626,7 @@ static int py3initialised = 0; #define WIN_PYTHON_REF(win) win->w_python3_ref #define BUF_PYTHON_REF(buf) buf->b_python3_ref +#define TAB_PYTHON_REF(tab) tab->tp_python3_ref static void call_PyObject_Free(void *p) @@ -652,6 +653,7 @@ call_PyType_GenericAlloc(PyTypeObject *t static PyObject *OutputGetattro(PyObject *, PyObject *); static int OutputSetattro(PyObject *, PyObject *, PyObject *); static PyObject *BufferGetattro(PyObject *, PyObject *); +static PyObject *TabPageGetattro(PyObject *, PyObject *); static PyObject *WindowGetattro(PyObject *, PyObject *); static int WindowSetattro(PyObject *, PyObject *, PyObject *); static PyObject *RangeGetattro(PyObject *, PyObject *); @@ -1275,6 +1277,26 @@ RangeAsSubscript(PyObject *self, PyObjec } } +/* TabPage object - Implementation + */ + + static PyObject * +TabPageGetattro(PyObject *self, PyObject *nameobj) +{ + PyObject *r; + + GET_ATTR_STRING(name, nameobj); + + if (CheckTabPage((TabPageObject *)(self))) + return NULL; + + r = TabPageAttr((TabPageObject *)(self), name); + if (r || PyErr_Occurred()) + return r; + else + return PyObject_GenericGetAttr(self, nameobj); +} + /* Window object - Implementation */ @@ -1303,6 +1325,22 @@ WindowSetattro(PyObject *self, PyObject return WindowSetattr(self, name, val); } +/* Tab page list object - Definitions + */ + +static PySequenceMethods TabListAsSeq = { + (lenfunc) TabListLength, /* sq_length, len(x) */ + (binaryfunc) 0, /* sq_concat, x+y */ + (ssizeargfunc) 0, /* sq_repeat, x*n */ + (ssizeargfunc) TabListItem, /* sq_item, x[i] */ + 0, /* sq_slice, x[i:j] */ + (ssizeobjargproc)0, /* sq_as_item, x[i]=v */ + 0, /* sq_ass_slice, x[i:j]=v */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + /* Window list object - Definitions */ @@ -1497,6 +1535,17 @@ python3_window_free(win_T *win) WIN_PYTHON_REF(win) = NULL; } } + + void +python3_tabpage_free(tabpage_T *tab) +{ + if (TAB_PYTHON_REF(tab) != NULL) + { + TabPageObject *tp = TAB_PYTHON_REF(tab); + tp->tab = INVALID_TABPAGE_VALUE; + TAB_PYTHON_REF(tab) = NULL; + } +} #endif static BufMapObject TheBufferMap = @@ -1507,6 +1556,7 @@ static BufMapObject TheBufferMap = static WinListObject TheWindowList = { PyObject_HEAD_INIT(&WinListType) + NULL }; static CurrentObject TheCurrent = @@ -1514,6 +1564,11 @@ static CurrentObject TheCurrent = PyObject_HEAD_INIT(&CurrentType) }; +static TabListObject TheTabPageList = +{ + PyObject_HEAD_INIT(&TabListType) +}; + static PyObject * Py3Init_vim(void) { @@ -1526,8 +1581,10 @@ Py3Init_vim(void) PyType_Ready(&BufferType); PyType_Ready(&RangeType); PyType_Ready(&WindowType); + PyType_Ready(&TabPageType); PyType_Ready(&BufMapType); PyType_Ready(&WinListType); + PyType_Ready(&TabListType); PyType_Ready(&CurrentType); PyType_Ready(&DictionaryType); PyType_Ready(&ListType); @@ -1551,6 +1608,8 @@ Py3Init_vim(void) PyModule_AddObject(mod, "current", (PyObject *)(void *)&TheCurrent); Py_INCREF((PyObject *)(void *)&TheWindowList); PyModule_AddObject(mod, "windows", (PyObject *)(void *)&TheWindowList); + Py_INCREF((PyObject *)(void *)&TheTabPageList); + PyModule_AddObject(mod, "tabpages", (PyObject *)(void *)&TheTabPageList); PyModule_AddObject(mod, "vars", DictionaryNew(&globvardict)); PyModule_AddObject(mod, "vvars", DictionaryNew(&vimvardict)); diff --git a/src/proto/if_python.pro b/src/proto/if_python.pro --- a/src/proto/if_python.pro +++ b/src/proto/if_python.pro @@ -6,6 +6,7 @@ void ex_python __ARGS((exarg_T *eap)); void ex_pyfile __ARGS((exarg_T *eap)); void python_buffer_free __ARGS((buf_T *buf)); void python_window_free __ARGS((win_T *win)); +void python_tabpage_free __ARGS((tabpage_T *tab)); void do_pyeval __ARGS((char_u *str, typval_T *rettv)); void set_ref_in_python __ARGS((int copyID)); /* vim: set ft=c : */ diff --git a/src/proto/if_python3.pro b/src/proto/if_python3.pro --- a/src/proto/if_python3.pro +++ b/src/proto/if_python3.pro @@ -6,6 +6,7 @@ void ex_py3 __ARGS((exarg_T *eap)); void ex_py3file __ARGS((exarg_T *eap)); void python3_buffer_free __ARGS((buf_T *buf)); void python3_window_free __ARGS((win_T *win)); +void python3_tabpage_free __ARGS((tabpage_T *tab)); void do_py3eval __ARGS((char_u *str, typval_T *rettv)); void set_ref_in_python3 __ARGS((int copyID)); /* vim: set ft=c : */ diff --git a/src/proto/window.pro b/src/proto/window.pro --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -74,5 +74,6 @@ int match_add __ARGS((win_T *wp, char_u int match_delete __ARGS((win_T *wp, int id, int perr)); void clear_matches __ARGS((win_T *wp)); matchitem_T *get_match __ARGS((win_T *wp, int id)); -int get_win_number __ARGS((win_T *wp)); +int get_win_number __ARGS((win_T *wp, win_T *first_win)); +int get_tab_number __ARGS((tabpage_T *tp)); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1759,6 +1759,14 @@ struct tabpage_S dictitem_T tp_winvar; /* variable for "t:" Dictionary */ dict_T *tp_vars; /* internal variables, local to tab page */ #endif + +#ifdef FEAT_PYTHON + void *tp_python_ref; /* The Python value for this tab page */ +#endif + +#ifdef FEAT_PYTHON3 + void *tp_python3_ref; /* The Python value for this tab page */ +#endif }; /* diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 949, +/**/ 948, /**/ 947, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -3510,6 +3510,15 @@ free_tabpage(tp) hash_init(&tp->tp_vars->dv_hashtab); unref_var_dict(tp->tp_vars); #endif + +#ifdef FEAT_PYTHON + python_tabpage_free(tp); +#endif + +#ifdef FEAT_PYTHON3 + python3_tabpage_free(tp); +#endif + vim_free(tp); } @@ -6734,12 +6743,12 @@ get_match(wp, id) #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO) int -get_win_number(win_T *wp) +get_win_number(win_T *wp, win_T *first_win) { int i = 1; win_T *w; - for (w = firstwin; w != NULL && w != wp; w = W_NEXT(w)) + for (w = first_win; w != NULL && w != wp; w = W_NEXT(w)) ++i; if (w == NULL) @@ -6747,4 +6756,19 @@ get_win_number(win_T *wp) else return i; } -#endif + + int +get_tab_number(tabpage_T *tp) +{ + int i = 1; + tabpage_T *t; + + for (t = first_tabpage; t != NULL && t != tp; t = t->tp_next) + ++i; + + if (t == NULL) + return 0; + else + return i; +} +#endif