*** src/eval.c.orig	2013-05-17 18:24:32.000000000 -0700
--- src/eval.c	2013-05-28 16:54:10.000000000 -0700
*************** static void f_atan2 __ARGS((typval_T *ar
*** 466,471 ****
--- 466,472 ----
  #endif
  static void f_browse __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_browsedir __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_bufinfo __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_bufexists __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_buflisted __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_bufloaded __ARGS((typval_T *argvars, typval_T *rettv));
*************** static void f_synstack __ARGS((typval_T 
*** 717,722 ****
--- 718,724 ----
  static void f_synconcealed __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_system __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_tabpagebuflist __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_tabpageinfo __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_tabpagenr __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_tabpagewinnr __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_taglist __ARGS((typval_T *argvars, typval_T *rettv));
*************** static void f_wildmenumode __ARGS((typva
*** 743,748 ****
--- 745,751 ----
  static void f_winbufnr __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_wincol __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_winheight __ARGS((typval_T *argvars, typval_T *rettv));
+ static void f_wininfo __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_winline __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_winnr __ARGS((typval_T *argvars, typval_T *rettv));
  static void f_winrestcmd __ARGS((typval_T *argvars, typval_T *rettv));
*************** static void getwinvar __ARGS((typval_T *
*** 825,830 ****
--- 828,834 ----
  static int searchpair_cmn __ARGS((typval_T *argvars, pos_T *match_pos));
  static int search_cmn __ARGS((typval_T *argvars, pos_T *match_pos, int *flagsp));
  static void setwinvar __ARGS((typval_T *argvars, typval_T *rettv, int off));
+ static int dict_add_dict(dict_T *d, char *key, dict_T *dict);
  
  
  #ifdef EBCDIC
*************** dict_add_list(d, key, list)
*** 7284,7289 ****
--- 7288,7320 ----
  }
  
  /*
+  * Add a dict entry to dictionary "d".
+  * Returns FAIL when out of memory and when key already exists.
+  */
+     static int
+ dict_add_dict(d, key, dict)
+     dict_T	*d;
+     char	*key;
+     dict_T	*dict;
+ {
+     dictitem_T	*item;
+ 
+     item = dictitem_alloc((char_u *)key);
+     if (item == NULL)
+ 	return FAIL;
+     item->di_tv.v_lock = 0;
+     item->di_tv.v_type = VAR_DICT;
+     item->di_tv.vval.v_dict = dict;
+     if (dict_add(d, item) == FAIL)
+     {
+ 	dictitem_free(item);
+ 	return FAIL;
+     }
+     ++dict->dv_refcount;
+     return OK;
+ }
+ 
+ /*
   * Get the number of items in a Dictionary.
   */
      static long
*************** static struct fst
*** 7848,7853 ****
--- 7879,7885 ----
      {"buffer_exists",	1, 1, f_bufexists},	/* obsolete */
      {"buffer_name",	1, 1, f_bufname},	/* obsolete */
      {"buffer_number",	1, 1, f_bufnr},		/* obsolete */
+     {"bufinfo",		0, 1, f_bufinfo},
      {"buflisted",	1, 1, f_buflisted},
      {"bufloaded",	1, 1, f_bufloaded},
      {"bufname",		1, 1, f_bufname},
*************** static struct fst
*** 8102,8107 ****
--- 8134,8140 ----
      {"synstack",	2, 2, f_synstack},
      {"system",		1, 2, f_system},
      {"tabpagebuflist",	0, 1, f_tabpagebuflist},
+     {"tabpageinfo",	0, 1, f_tabpageinfo},
      {"tabpagenr",	0, 1, f_tabpagenr},
      {"tabpagewinnr",	1, 2, f_tabpagewinnr},
      {"tagfiles",	0, 0, f_tagfiles},
*************** static struct fst
*** 8128,8133 ****
--- 8161,8167 ----
      {"winbufnr",	1, 1, f_winbufnr},
      {"wincol",		0, 0, f_wincol},
      {"winheight",	1, 1, f_winheight},
+     {"wininfo",		0, 2, f_wininfo},
      {"winline",		0, 0, f_winline},
      {"winnr",		0, 1, f_winnr},
      {"winrestcmd",	0, 0, f_winrestcmd},
*************** find_buffer(avar)
*** 8973,8978 ****
--- 9007,9252 ----
  }
  
  /*
+  * get_buffer_options
+  * Return all the buffer-local options in a dictionary.
+  */
+     static dict_T *
+ get_buffer_options(buf)
+     buf_T	*buf;
+ {
+     dict_T	*opts;
+ 
+     /* Copy buffer options */
+     opts = dict_alloc();
+     if (opts == NULL)
+ 	return NULL;
+ 
+     dict_add_nr_str(opts, "autoindent", buf->b_p_ai, NULL);
+     dict_add_nr_str(opts, "copyindent", buf->b_p_ci, NULL);
+     dict_add_nr_str(opts, "binary", buf->b_p_bin, NULL);
+ #ifdef FEAT_MBYTE
+     dict_add_nr_str(opts, "bomb", buf->b_p_bomb, NULL);
+ #endif
+ #ifdef FEAT_QUICKFIX
+     dict_add_nr_str(opts, "bufhidden", 0L, buf->b_p_bh);
+     dict_add_nr_str(opts, "buftype", 0L, buf->b_p_bt);
+ #endif
+     dict_add_nr_str(opts, "buflisted", buf->b_p_bl, NULL);
+ #ifdef FEAT_CINDENT
+     dict_add_nr_str(opts, "cindent", buf->b_p_cin, NULL);
+     dict_add_nr_str(opts, "cinoptions", 0L, buf->b_p_cino);
+     dict_add_nr_str(opts, "cinkeys", 0L, buf->b_p_cink);
+ #endif
+ #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
+     dict_add_nr_str(opts, "cinwords", 0L, buf->b_p_cinw);
+ #endif
+ #ifdef FEAT_COMMENTS
+     dict_add_nr_str(opts, "comments", 0L, buf->b_p_com);
+ #endif
+ #ifdef FEAT_FOLDING
+     dict_add_nr_str(opts, "commentstring", 0L, buf->b_p_cms);
+ #endif
+ #ifdef FEAT_INS_EXPAND
+     dict_add_nr_str(opts, "complete", 0L, buf->b_p_cpt);
+ #endif
+ #ifdef FEAT_COMPL_FUNC
+     dict_add_nr_str(opts, "completefunc", 0L, buf->b_p_cfu);
+     dict_add_nr_str(opts, "omnifunc", 0L, buf->b_p_ofu);
+ #endif
+     dict_add_nr_str(opts, "endofline", buf->b_p_eol, NULL);
+     dict_add_nr_str(opts, "expandtab", buf->b_p_et, NULL);
+ #ifdef FEAT_MBYTE
+     dict_add_nr_str(opts, "fileencoding", 0L, buf->b_p_fenc);
+ #endif
+     dict_add_nr_str(opts, "fileformat", 0L, buf->b_p_ff);
+ #ifdef FEAT_AUTOCMD
+     dict_add_nr_str(opts, "filetype", 0L, buf->b_p_ft);
+ #endif
+     dict_add_nr_str(opts, "formatoptions", 0L, buf->b_p_fo);
+     dict_add_nr_str(opts, "formatlistpat", 0L, buf->b_p_flp);
+     dict_add_nr_str(opts, "infercase", buf->b_p_inf, NULL);
+     dict_add_nr_str(opts, "iskeyword", 0L, buf->b_p_isk);
+ #ifdef FEAT_FIND_ID
+     dict_add_nr_str(opts, "define", 0L, buf->b_p_def);
+     dict_add_nr_str(opts, "include", 0L, buf->b_p_inc);
+ # ifdef FEAT_EVAL
+     dict_add_nr_str(opts, "includeexpr", 0L, buf->b_p_inex);
+ # endif
+ #endif
+ #if defined(FEAT_CINDENT) && defined(FEAT_EVAL)
+     dict_add_nr_str(opts, "indentexpr", 0L, buf->b_p_inde);
+     dict_add_nr_str(opts, "indentkeys", 0L, buf->b_p_indk);
+ #endif
+ #ifdef FEAT_EVAL
+     dict_add_nr_str(opts, "formatexpr", 0L, buf->b_p_fex);
+ #endif
+ #ifdef FEAT_CRYPT
+     dict_add_nr_str(opts, "key", 0L, buf->b_p_key);
+ #endif
+     dict_add_nr_str(opts, "keywordprg", 0L, buf->b_p_kp);
+ #ifdef FEAT_LISP
+     dict_add_nr_str(opts, "lisp", buf->b_p_lisp, NULL);
+ #endif
+     dict_add_nr_str(opts, "matchpairs", 0L, buf->b_p_mps);
+     dict_add_nr_str(opts, "modeline", buf->b_p_ml, NULL);
+     dict_add_nr_str(opts, "modifiable", buf->b_p_ma, NULL);
+     dict_add_nr_str(opts, "nrformats", 0L, buf->b_p_nf);
+     dict_add_nr_str(opts, "preserveindent", buf->b_p_pi, NULL);
+ #ifdef FEAT_TEXTOBJ
+     dict_add_nr_str(opts, "quoteescape", 0L, buf->b_p_qe);
+ #endif
+     dict_add_nr_str(opts, "readonly", buf->b_p_ro, NULL);
+     dict_add_nr_str(opts, "shiftwidth", buf->b_p_sw, NULL);
+ #ifndef SHORT_FNAME
+     dict_add_nr_str(opts, "shortname", buf->b_p_sn, NULL);
+ #endif
+ #ifdef FEAT_SMARTINDENT
+     dict_add_nr_str(opts, "smartindent", buf->b_p_si, NULL);
+ #endif
+     dict_add_nr_str(opts, "softtabstop", buf->b_p_sts, NULL);
+ #ifdef FEAT_SEARCHPATH
+     dict_add_nr_str(opts, "suffixesadd", 0L, buf->b_p_sua);
+ #endif
+     dict_add_nr_str(opts, "swapfile", buf->b_p_swf, NULL);
+ #ifdef FEAT_SYN_HL
+     dict_add_nr_str(opts, "synmaxcol", buf->b_p_smc, NULL);
+     dict_add_nr_str(opts, "syntax", 0L, buf->b_p_syn);
+ #endif
+     dict_add_nr_str(opts, "tabstop", buf->b_p_ts, NULL);
+     dict_add_nr_str(opts, "textwidth", buf->b_p_tw, NULL);
+     dict_add_nr_str(opts, "wrapmargin", buf->b_p_wm, NULL);
+ #ifdef FEAT_KEYMAP
+     dict_add_nr_str(opts, "keymap", 0L, buf->b_p_keymap);
+ #endif
+ #ifdef FEAT_QUICKFIX
+     dict_add_nr_str(opts, "grepprg", 0L, buf->b_p_gp);
+     dict_add_nr_str(opts, "makeprg", 0L, buf->b_p_mp);
+     dict_add_nr_str(opts, "errorformat", 0L, buf->b_p_efm);
+ #endif
+     dict_add_nr_str(opts, "equalprg", 0L, buf->b_p_ep);
+     dict_add_nr_str(opts, "path", 0L, buf->b_p_path);
+     dict_add_nr_str(opts, "autoread", buf->b_p_ar, NULL);
+     dict_add_nr_str(opts, "tags", 0L, buf->b_p_tags);
+ #ifdef FEAT_INS_EXPAND
+     dict_add_nr_str(opts, "dictionary", 0L, buf->b_p_dict);
+     dict_add_nr_str(opts, "thesaurus", 0L, buf->b_p_tsr);
+ #endif
+ #ifdef FEAT_PERSISTENT_UNDO
+     dict_add_nr_str(opts, "undofile", buf->b_p_udf, NULL);
+ #endif
+ #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
+     dict_add_nr_str(opts, "balloonexpr", 0L, buf->b_p_bexpr);
+ #endif
+ #ifdef FEAT_CRYPT
+     dict_add_nr_str(opts, "cryptmethod", 0L, buf->b_p_cm);
+ #endif
+ 
+     return opts;
+ }
+ 
+ /*
+  * Returns buffer options, variables and other attributes in a dictionary
+  */
+     static dict_T *
+ get_buffer_info(buf)
+     buf_T	*buf;
+ {
+     dict_T	*dict;
+     dict_T	*opts;
+     dict_T	*vars;
+ 
+     dict = dict_alloc();
+     if (dict == NULL)
+ 	return NULL;
+ 
+     dict_add_nr_str(dict, "nr", buf->b_fnum, NULL);
+     dict_add_nr_str(dict, "name", 0L, buf->b_ffname);
+     dict_add_nr_str(dict, "lnum", buflist_findlnum(buf), NULL);
+     dict_add_nr_str(dict, "loaded", buf->b_ml.ml_mfp != NULL, NULL);
+     dict_add_nr_str(dict, "changed", bufIsChanged(buf), NULL);
+     dict_add_nr_str(dict, "changedtick", buf->b_changedtick, NULL);
+     dict_add_nr_str(dict, "hidden",
+ 		    buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0,
+ 		    NULL);
+ 
+     /* Copy buffer variables */
+     vars = dict_copy(buf->b_vars, TRUE, 0);
+     if (vars != NULL)
+ 	dict_add_dict(dict, "variables", vars);
+ 
+     /* Copy buffer options */
+     opts = get_buffer_options(buf);
+     if (opts != NULL)
+ 	dict_add_dict(dict, "options", opts);
+ 
+     return dict;
+ }
+ 
+ static buf_T *get_buf_tv __ARGS((typval_T *tv, int curtab_only));
+ 
+     static void
+ rettv_dict_set(rettv, d)
+     typval_T	*rettv;
+     dict_T	*d;
+ {
+     if (d == NULL)
+ 	return;
+     rettv->v_type = VAR_DICT;
+     rettv->vval.v_dict = d;
+     ++d->dv_refcount;
+ }
+ 
+ /*
+  * "bufinfo()" function
+  */
+     static void
+ f_bufinfo(argvars, rettv)
+     typval_T	*argvars UNUSED;
+     typval_T	*rettv;
+ {
+     buf_T	*buf = NULL;
+     buf_T	*argbuf = NULL;
+     dict_T	*d;
+ 
+     if (argvars[0].v_type == VAR_UNKNOWN)
+     {
+ 	/* List of all the buffers */
+ 	if (rettv_list_alloc(rettv) != OK)
+ 	    return;
+     }
+     else
+     {
+ 	/* Information about one buffer.  Argument specifies the buffer */
+ 	(void)get_tv_number(&argvars[0]);   /* issue errmsg if type error */
+ 	++emsg_off;
+ 	argbuf = get_buf_tv(&argvars[0], FALSE);
+ 	--emsg_off;
+ 	if (argbuf == NULL)
+ 	{
+ 	    (void)rettv_dict_alloc(rettv);
+ 	    return;
+ 	}
+     }
+ 
+     /* Return information about all the buffers or a specified buffer */
+     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
+     {
+ 	if (argbuf != NULL && argbuf != buf)
+ 	    continue;
+ 
+ 	d = get_buffer_info(buf);
+ 	if (argbuf != NULL)
+ 	{
+ 	    rettv_dict_set(rettv, d);
+ 	    return;
+ 	}
+ 
+ 	if (d != NULL)
+ 	    list_append_dict(rettv->vval.v_list, d);
+     }
+ }
+ 
+ /*
   * "bufexists(expr)" function
   */
      static void
*************** f_bufloaded(argvars, rettv)
*** 9011,9018 ****
      rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
  }
  
- static buf_T *get_buf_tv __ARGS((typval_T *tv, int curtab_only));
- 
  /*
   * Get buffer by number or pattern.
   */
--- 9285,9290 ----
*************** f_settabvar(argvars, rettv)
*** 16589,16594 ****
--- 16861,16867 ----
  
      rettv->vval.v_number = 0;
  
+ #ifdef FEAT_WINDOWS
      if (check_restricted() || check_secure())
  	return;
  
*************** f_settabvar(argvars, rettv)
*** 16614,16619 ****
--- 16887,16893 ----
  	if (valid_tabpage(save_curtab))
  	    goto_tabpage_tp(save_curtab, FALSE, FALSE);
      }
+ #endif
  }
  
  /*
*************** f_tabpagebuflist(argvars, rettv)
*** 17972,17977 ****
--- 18246,18338 ----
  #endif
  }
  
+ #ifdef FEAT_WINDOWS
+ /*
+  * get_tabpage_info
+  * Returns information (variables, options, etc.) about a tab page
+  * as a dictionary
+  */
+     static dict_T *
+ get_tabpage_info(tp, tp_idx)
+     tabpage_T	*tp;
+     int		tp_idx;
+ {
+     win_T	*wp;
+     dict_T	*dict;
+     dict_T	*vars;
+     int		nr;
+ 
+     dict = dict_alloc();
+     if (dict == NULL)
+ 	return NULL;
+ 
+     dict_add_nr_str(dict, "nr", tp_idx, NULL);
+ 
+     /* Count the number of windows in this tab page */
+     nr = 1;
+     for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ 	 wp != ((tp == curtab) ? lastwin : tp->tp_lastwin);
+ 	 wp = wp->w_next)
+ 	nr++;
+     dict_add_nr_str(dict, "numwindows", nr, NULL);
+ 
+     /* Copy tabpage variables */
+     vars = dict_copy(tp->tp_vars, TRUE, 0);
+     if (vars != NULL)
+ 	dict_add_dict(dict, "variables", vars);
+ 
+     return dict;
+ }
+ #endif
+ 
+ /*
+  * "tabpageinfo()" function
+  */
+     static void
+ f_tabpageinfo(argvars, rettv)
+     typval_T	*argvars UNUSED;
+     typval_T	*rettv;
+ {
+ #ifdef FEAT_WINDOWS
+     tabpage_T	*tp, *tparg = NULL;
+     dict_T	*d;
+     int		tpnr = 1;
+ 
+     if (argvars[0].v_type == VAR_UNKNOWN)
+     {
+ 	/* List of all the tab pages */
+ 	if (rettv_list_alloc(rettv) != OK)
+ 	    return;
+     }
+     else
+     {
+ 	/* Information about one tab page */
+ 	tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
+ 	if (tparg == NULL)
+ 	{
+ 	    (void)rettv_dict_alloc(rettv);
+ 	    return;
+ 	}
+     }
+ 
+     /* Get information about a specific tab page or all tab pages */
+     for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, tpnr++)
+     {
+ 	if (tparg != NULL && tp != tparg)
+ 	    continue;
+ 
+ 	d = get_tabpage_info(tp, tpnr);
+ 	if (tparg != NULL)
+ 	{
+ 	    rettv_dict_set(rettv, d);
+ 	    return;
+ 	}
+ 
+ 	if (d != NULL)
+ 	    list_append_dict(rettv->vval.v_list, d);
+     }
+ #endif
+ }
  
  /*
   * "tabpagenr()" function
*************** f_winheight(argvars, rettv)
*** 18629,18634 ****
--- 18990,19194 ----
  }
  
  /*
+  * get_win_options
+  * Return all the window-local options in a dictionary.
+  */
+     static dict_T *
+ get_win_options(wp)
+     win_T	*wp;
+ {
+     dict_T	*opts;
+ 
+     /* Copy window options */
+     opts = dict_alloc();
+     if (opts == NULL)
+ 	return NULL;
+ 
+ #ifdef FEAT_ARABIC
+     dict_add_nr_str(opts, "arabic", wp->w_p_arab, NULL);
+ #endif
+ #ifdef FEAT_DIFF
+     dict_add_nr_str(opts, "diff", wp->w_p_diff, NULL);
+ #endif
+ #ifdef FEAT_FOLDING
+     dict_add_nr_str(opts, "foldcolumn", wp->w_p_fdc, NULL);
+     dict_add_nr_str(opts, "foldenable", wp->w_p_fen, NULL);
+     dict_add_nr_str(opts, "foldignore", 0L, wp->w_p_fdi);
+     dict_add_nr_str(opts, "foldlevel", wp->w_p_fdl, NULL);
+     dict_add_nr_str(opts, "foldmethod", 0L, wp->w_p_fdm);
+     dict_add_nr_str(opts, "foldminlines", wp->w_p_fml, NULL);
+     dict_add_nr_str(opts, "foldnestmax", wp->w_p_fdn, NULL);
+ # ifdef FEAT_EVAL
+     dict_add_nr_str(opts, "foldexpr", 0L, wp->w_p_fde);
+     dict_add_nr_str(opts, "foldtext", 0L, wp->w_p_fdt);
+ # endif
+     dict_add_nr_str(opts, "foldmarker", 0L, wp->w_p_fmr);
+ #endif
+ #ifdef FEAT_LINEBREAK
+     dict_add_nr_str(opts, "linebreak", wp->w_p_lbr, NULL);
+ #endif
+     dict_add_nr_str(opts, "list", wp->w_p_list, NULL);
+     dict_add_nr_str(opts, "number", wp->w_p_nu, NULL);
+     dict_add_nr_str(opts, "relativenumber", wp->w_p_rnu, NULL);
+ #ifdef FEAT_LINEBREAK
+     dict_add_nr_str(opts, "numberwidth", wp->w_p_nuw, NULL);
+ #endif
+ #ifdef FEAT_WINDOWS
+     dict_add_nr_str(opts, "winfixheight", wp->w_p_wfh, NULL);
+     dict_add_nr_str(opts, "winfixwidth", wp->w_p_wfw, NULL);
+ #endif
+ #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX)
+     dict_add_nr_str(opts, "previewwindow", wp->w_p_pvw, NULL);
+ #endif
+ #ifdef FEAT_RIGHTLEFT
+     dict_add_nr_str(opts, "rightleft", wp->w_p_rl, NULL);
+     dict_add_nr_str(opts, "rightleftcmd", 0L, wp->w_p_rlc);
+ #endif
+     dict_add_nr_str(opts, "scroll", wp->w_p_scr, NULL);
+ #ifdef FEAT_SPELL
+     dict_add_nr_str(opts, "spell", wp->w_p_spell, NULL);
+ #endif
+ #ifdef FEAT_SYN_HL
+     dict_add_nr_str(opts, "cursorcolumn", wp->w_p_cuc, NULL);
+     dict_add_nr_str(opts, "cursorline", wp->w_p_cul, NULL);
+     dict_add_nr_str(opts, "colorcolumn", 0L, wp->w_p_cc);
+ #endif
+ #ifdef FEAT_STL_OPT
+     dict_add_nr_str(opts, "statusline", 0L, wp->w_p_stl);
+ #endif
+ #ifdef FEAT_SCROLLBIND
+     dict_add_nr_str(opts, "scrollbind", wp->w_p_scb, NULL);
+ #endif
+     dict_add_nr_str(opts, "wrap", wp->w_p_wrap, NULL);
+ #ifdef FEAT_CONCEAL
+     dict_add_nr_str(opts, "concealcursor", 0L, wp->w_p_cocu);
+     dict_add_nr_str(opts, "conceallevel", wp->w_p_cole, NULL);
+ #endif
+ #ifdef FEAT_CURSORBIND
+     dict_add_nr_str(opts, "cursorbind", wp->w_p_crb, NULL);
+ #endif
+ 
+     return opts;
+ }
+ 
+ #ifdef FEAT_WINDOWS
+ /*
+  * Returns information about a window as a dictionary
+  */
+     static dict_T *
+ get_win_info(wp, tpnr, winnr)
+     win_T   *wp;
+     short   tpnr;
+     short   winnr;
+ {
+     dict_T	*dict;
+     dict_T	*vars;
+     dict_T	*opts;
+ 
+     dict = dict_alloc();
+     if (dict == NULL)
+ 	return NULL;
+ 
+     dict_add_nr_str(dict, "tpnr", tpnr, NULL);
+     dict_add_nr_str(dict, "nr", winnr, NULL);
+     dict_add_nr_str(dict, "height", wp->w_height, NULL);
+     dict_add_nr_str(dict, "width", wp->w_width, NULL);
+     dict_add_nr_str(dict, "bufnum", wp->w_buffer->b_fnum, NULL);
+ 
+     /* Copy window variables */
+     vars = dict_copy(wp->w_vars, TRUE, 0);
+     if (vars != NULL)
+ 	dict_add_dict(dict, "variables", vars);
+ 
+     /* Copy window options */
+     opts = get_win_options(wp);
+     if (opts != NULL)
+ 	dict_add_dict(dict, "options", opts);
+ 
+     return dict;
+ }
+ #endif
+ 
+ /*
+  * "wininfo()" function
+  */
+     static void
+ f_wininfo(argvars, rettv)
+     typval_T	*argvars;
+     typval_T	*rettv;
+ {
+ #ifdef FEAT_WINDOWS
+     tabpage_T	*tp, *tparg = NULL;
+     win_T	*wp = NULL, *wparg = NULL;
+     dict_T	*d;
+     short	tpnr, winnr;
+ #endif
+ 
+     if (argvars[0].v_type == VAR_UNKNOWN || argvars[1].v_type == VAR_UNKNOWN)
+     {
+ 	/* collect information about a list of windows */
+ 	if (rettv_list_alloc(rettv) != OK)
+ 	    return;
+     }
+ 
+ #ifdef FEAT_WINDOWS
+     if (argvars[0].v_type != VAR_UNKNOWN)
+     {
+ 	/* first argument is the tab page number */
+ 	tparg = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
+ 	if (tparg == NULL)
+ 	{
+ 	    if (argvars[1].v_type != VAR_UNKNOWN)
+ 		/* return an empty dictionary */
+ 		(void)rettv_dict_alloc(rettv);
+ 	    return;
+ 	}
+ 
+ 	if (argvars[1].v_type != VAR_UNKNOWN)
+ 	{
+ 	    /* second argument is the window number */
+ 	    wparg = find_win_by_nr(&argvars[1], tparg);
+ 	    if (wparg == NULL)
+ 	    {
+ 		(void)rettv_dict_alloc(rettv);
+ 		return;
+ 	    }
+ 	}
+     }
+ 
+     /* collect information about either all the windows across all the tab
+      * pages or one particular window.
+      */
+     tpnr = 1;
+     for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, tpnr++)
+     {
+ 	if (tparg != NULL && tp != tparg)
+ 	    continue;
+ 
+ 	wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
+ 	winnr = 1;
+ 
+ 	for (; wp; wp = wp->w_next, winnr++)
+ 	{
+ 	    if (wparg != NULL && wp != wparg)
+ 		continue;
+ 
+ 	    d = get_win_info(wp, tpnr, winnr);
+ 	    if (wparg != NULL)
+ 	    {
+ 		/* found information about a specific window */
+ 		rettv_dict_set(rettv, d);
+ 		return;
+ 	    }
+ 
+ 	    if (d != NULL)
+ 		list_append_dict(rettv->vval.v_list, d);
+ 	}
+     }
+ #endif
+ }
+ 
+ /*
   * "winline()" function
   */
      static void
*** runtime/doc/eval.txt.orig	2013-05-17 18:24:31.000000000 -0700
--- runtime/doc/eval.txt	2013-05-28 16:52:54.000000000 -0700
*************** atan2( {expr}, {expr})		Float   arc tang
*** 1704,1709 ****
--- 1704,1710 ----
  browse( {save}, {title}, {initdir}, {default})
  				String	put up a file requester
  browsedir( {title}, {initdir})	String	put up a directory requester
+ bufinfo( [{expr}])		List/Dict  list of buffers
  bufexists( {expr})		Number	TRUE if buffer {expr} exists
  buflisted( {expr})		Number	TRUE if buffer {expr} is listed
  bufloaded( {expr})		Number	TRUE if buffer {expr} is loaded
*************** synIDtrans( {synID})		Number	translated 
*** 1976,1981 ****
--- 1977,1983 ----
  synconcealed( {lnum}, {col})	List    info about concealing
  synstack( {lnum}, {col})	List	stack of syntax IDs at {lnum} and {col}
  system( {expr} [, {input}])	String	output of shell command/filter {expr}
+ tabpageinfo( [{expr}])		List/Dict  list of tab pages
  tabpagebuflist( [{arg}])	List	list of buffer numbers in tab page
  tabpagenr( [{arg}])		Number	number of current or last tab page
  tabpagewinnr( {tabarg}[, {arg}])
*************** winbufnr( {nr})			Number	buffer number o
*** 2001,2006 ****
--- 2003,2010 ----
  wincol()			Number	window column of the cursor
  winheight( {nr})		Number	height of window {nr}
  winline()			Number	window line of the cursor
+ wininfo( [{tpnr} [, {winnr}]])
+ 				List/Dict  list of windows
  winnr( [{expr}])		Number	number of current window
  winrestcmd()			String	returns command to restore window sizes
  winrestview( {dict})		none	restore view of current window
*************** browsedir({title}, {initdir})
*** 2149,2154 ****
--- 2153,2176 ----
  		When the "Cancel" button is hit, something went wrong, or
  		browsing is not possible, an empty string is returned.
  
+ bufinfo([{expr}])					*bufinfo()*
+ 		If {expr} is not specified, then information about all the
+ 		buffers is returned as a List. Each list item is a dictionary.
+ 		Otherwise, {expr} specifies a particular buffer to be used and
+ 		a Dict is returned.  For the use of {expr}, see |bufname()|
+ 		above.
+ 
+ 		Each list item is a dictionary with the following entries:
+ 			changed		TRUE if the buffer is modified.
+ 			changedtick	number of changes made to the buffer.
+ 			hidden		TRUE if the buffer is hidden.
+ 			lnum		current line number in buffer.
+ 			loaded		TRUE if the buffer is loaded.
+ 			name		full path to the file in the buffer.
+ 			nr		buffer number.
+ 			options		dictionary of buffer local options.
+ 			variables	dictionary of buffer local variables.
+ 
  bufexists({expr})					*bufexists()*
  		The result is a Number, which is non-zero if a buffer called
  		{expr} exists.
*************** system({expr} [, {input}])				*system()*
*** 5885,5890 ****
--- 5907,5922 ----
  		Use |:checktime| to force a check.
  
  
+ tabpageinfo([{arg}])					*tabpageinfo()*
+ 		If {arg} is not specified, then information about all the tab
+ 		pages is returned as a List. Each list item is a dictionary.
+ 		Otherwise, {arg} specifies the number of tab page to be used
+ 		and a Dict is returned.
+ 		Each list item is a dictionary with the following entries:
+ 			nr		tab page number.
+ 			numwindows	number of windows in the tab page.
+ 			variables	dictionary of tabpage local variables.
+ 
  tabpagebuflist([{arg}])					*tabpagebuflist()*
  		The result is a |List|, where each item is the number of the
  		buffer associated with each window in the current tab page.
*************** winheight({nr})						*winheight()*
*** 6201,6206 ****
--- 6233,6256 ----
  		Examples: >
    :echo "The current window has " . winheight(0) . " lines."
  <
+ wininfo([{tpnr}, [{winnr}]])				*wininfo()*
+ 		Returns information about windows as a List or a Dict.
+ 		{tpnr} specifies the tab page number and {winnr} specifies the
+ 		window number. If both are supplied, then information about
+ 		the specified window is returned as a Dict. If {winnr} is not
+ 		supplied, then information about all the windows in {tpnr} is
+ 		returned as a List. If both are not supplied, then
+ 		information about all the windows in all the tab pages is
+ 		returned as a List.
+ 		Each list item is a dictionary with the following entries:
+ 			nr		window number.
+ 			tpnr		tab page number.
+ 			height		window height.
+ 			width		window width.
+ 			bufnum		number of buffer in the window.
+ 			options		dictionary of window local options.
+ 			variables	dictionary of window local variables.
+ 
  							*winline()*
  winline()	The result is a Number, which is the screen line of the cursor
  		in the window.	This is counting screen lines from the top of
