Index: runtime/doc/index.txt
===================================================================
--- runtime/doc/index.txt	(revision 1586)
+++ runtime/doc/index.txt	(working copy)
@@ -1125,6 +1125,7 @@
 |:clast|	:cla[st]	go to the specified error, default last one
 |:close|	:clo[se]	close current window
 |:cmap|		:cm[ap]		like ":map" but for Command-line mode
+|:cdupmap|	:cdupm[ap]	like ":dupmap" but for Command-line mode
 |:cmapclear|	:cmapc[lear]	clear all mappings for Command-line mode
 |:cmenu|	:cme[nu]	add menu for Command-line mode
 |:cnext|	:cn[ext]	go to next error
@@ -1175,6 +1176,7 @@
 				current window
 |:dsearch|	:ds[earch]	list one #define
 |:dsplit|	:dsp[lit]	split window and jump to #define
+|:dupmap|	:dupmap		copy an existing mapping
 |:edit|		:e[dit]		edit a file
 |:earlier|	:ea[rlier]	go to older change, undo
 |:echo|		:ec[ho]		echoes the result of expressions
@@ -1227,6 +1229,7 @@
 |:insert|	:i[nsert]	insert text
 |:iabbrev|	:ia[bbrev]	like ":abbrev" but for Insert mode
 |:iabclear|	:iabc[lear]	like ":abclear" but for Insert mode
+|:idupmap|	:idupm[ap]	like ":dupmap" but for Insert mode
 |:if|		:if		execute commands when condition met
 |:ijump|	:ij[ump]	jump to definition of identifier
 |:ilist|	:il[ist]	list lines where identifier matches
@@ -1263,6 +1266,7 @@
 |:lchdir|	:lch[dir]	change directory locally
 |:lclose|	:lcl[ose]	close location window
 |:lcscope|	:lcs[cope]      like ":cscope" but uses location list
+|:ldupmap|	:ldupm[ap]	like ":dupmap!" but includes Lang-Arg mode
 |:left|		:le[ft]		left align lines
 |:leftabove|	:lefta[bove]	make split window appear left or above
 |:let|		:let		assign a value to a variable or option
@@ -1322,6 +1326,7 @@
 |:mzscheme|	:mz[scheme]	execute MzScheme command
 |:mzfile|	:mzf[ile]	execute MzScheme script file
 |:nbkey|	:nb[key]	pass a key to Netbeans
+|:ndupmap|	:dupnm[ap]	like ":dupmap" but for Normal mode
 |:next|		:n[ext]		go to next file in the argument list
 |:new|		:new		create a new empty window
 |:nmap|		:nm[ap]		like ":map" but for Normal mode
@@ -1339,6 +1344,7 @@
 |:number|	:nu[mber]	print lines with line number
 |:nunmap|	:nun[map]	like ":unmap" but for Normal mode
 |:nunmenu|	:nunme[nu]	remove menu for Normal mode
+|:odupmap|	:odupm[ap]	like ":dupmap" but for Operator-pending mode
 |:open|		:o[pen]		start open mode (not implemented)
 |:omap|		:om[ap]		like ":map" but for Operator-pending mode
 |:omapclear|	:omapc[lear]	remove all mappings for Operator-pending mode
@@ -1426,6 +1432,7 @@
 |:scriptnames|	:scrip[tnames]	list names of all sourced Vim scripts
 |:scriptencoding| :scripte[ncoding]	encoding used in sourced Vim script
 |:scscope|	:scs[cope]	split window and execute cscope command
+|:sdupmap|	:dupsma[p]	like ":dupmap" but for Select mode
 |:set|		:se[t]		show or set options
 |:setfiletype|	:setf[iletype]	set 'filetype', unless it was set already
 |:setglobal|	:setg[lobal]	show global values of options
@@ -1526,10 +1533,11 @@
 |:unmap|	:unm[ap]	remove mapping
 |:unmenu|	:unme[nu]	remove menu
 |:update|	:up[date]	write buffer if modified
-|:vglobal|	:v[global]	execute commands for not matching lines
+|:vdupmap|	:vdupm[ap]	like ":dupmap" but for Visual+Select mode
 |:version|	:ve[rsion]	print version number and other info
 |:verbose|	:verb[ose]	execute command with 'verbose' set
 |:vertical|	:vert[ical]	make following command split vertically
+|:vglobal|	:v[global]	execute commands for not matching lines
 |:vimgrep|	:vim[grep]	search for pattern in files
 |:vimgrepadd|	:vimgrepa[dd]	like :vimgrep, but append to current list
 |:visual|	:vi[sual]	same as ":edit", but turns off "Ex" mode
@@ -1561,6 +1569,7 @@
 |:wqall|	:wqa[ll]	write all changed buffers and quit Vim
 |:wsverb|	:ws[verb]	pass the verb to workshop over IPC
 |:wviminfo|	:wv[iminfo]	write to viminfo file
+|:xdupmap|	:xdupm[ap]	like ":dupmap" but for Visual mode
 |:xit|		:x[it]		write if buffer changed and quit window or Vim
 |:xall|		:xa[ll]		same as ":wqall"
 |:xmapclear|	:xmapc[lear]	remove all mappings for Visual mode
Index: runtime/doc/map.txt
===================================================================
--- runtime/doc/map.txt	(revision 1586)
+++ runtime/doc/map.txt	(working copy)
@@ -76,7 +76,22 @@
 			{rhs}, to avoid nested and recursive mappings.  Often
 			used to redefine a command.  {not in Vi}
 
+:dupmap	    {lhs} {rhs}		|mapmode-nvo|		*:dup*  *:dupmap*
+:ndup[map]  {lhs} {rhs}		|mapmode-n|		*:ndup* *:nupmap*
+:vdup[map]  {lhs} {rhs}		|mapmode-v|		*:vdup* *:vupmap*
+:xdup[map]  {lhs} {rhs}		|mapmode-x|		*:xdup* *:xupmap*
+:sdup[map]  {lhs} {rhs}		|mapmode-s|		*:snor* *:supmap*
+:odup[map]  {lhs} {rhs}		|mapmode-o|		*:odup* *:oupmap*
+:dup[map]!  {lhs} {rhs}		|mapmode-ic|		*:dup!* *:dupmap!*
+:idup[map]  {lhs} {rhs}		|mapmode-i|		*:idup* *:iupmap*
+:ldup[map]  {lhs} {rhs}		|mapmode-l|		*:ldup* *:lupmap*
+:cdup[map]  {lhs} {rhs}		|mapmode-c|		*:cdup* *:cupmap*
+			Duplicate the map represented by key sequence {lhs}
+			to {rhs} for the modes where the map command applies.
+			Often used to copy a command such that it can be
+			restored later.  {not in Vi}
 
+
 :unm[ap]  {lhs}			|mapmode-nvo|		*:unm*  *:unmap*
 :nun[map] {lhs}			|mapmode-n|		*:nun*  *:nunmap*
 :vu[nmap] {lhs}			|mapmode-v|		*:vu*   *:vunmap*
Index: src/netbeans.c
===================================================================
--- src/netbeans.c	(revision 1586)
+++ src/netbeans.c	(working copy)
@@ -2642,7 +2642,7 @@
 	strcpy(&keybuf[i], tok);
 	vim_snprintf(cmdbuf, sizeof(cmdbuf),
 				"<silent><%s> :nbkey %s<CR>", keybuf, keybuf);
-	do_map(0, (char_u *)cmdbuf, NORMAL, FALSE);
+	do_map(0, (char_u *)cmdbuf, NORMAL, FALSE, FALSE);
 	tok = strtok(NULL, " ");
     }
     vim_free(save_str);
Index: src/digraph.c
===================================================================
--- src/digraph.c	(revision 1586)
+++ src/digraph.c	(working copy)
@@ -2525,7 +2525,7 @@
 	vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s %s",
 				((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].from,
 				 ((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].to);
-	(void)do_map(2, buf, LANGMAP, FALSE);
+	(void)do_map(2, buf, LANGMAP, FALSE, FALSE);
     }
 
     p_cpo = save_cpo;
@@ -2558,7 +2558,7 @@
     for (i = 0; i < curbuf->b_kmap_ga.ga_len; ++i)
     {
 	vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s", kp[i].from);
-	(void)do_map(1, buf, LANGMAP, FALSE);
+	(void)do_map(1, buf, LANGMAP, FALSE, FALSE);
 	vim_free(kp[i].from);
 	vim_free(kp[i].to);
     }
Index: src/ex_docmd.c
===================================================================
--- src/ex_docmd.c	(revision 1586)
+++ src/ex_docmd.c	(working copy)
@@ -3743,12 +3743,12 @@
 	    }
 	    break;
 #endif
-	case CMD_map:	    case CMD_noremap:
-	case CMD_nmap:	    case CMD_nnoremap:
-	case CMD_vmap:	    case CMD_vnoremap:
-	case CMD_omap:	    case CMD_onoremap:
-	case CMD_imap:	    case CMD_inoremap:
-	case CMD_cmap:	    case CMD_cnoremap:
+	case CMD_map:	    case CMD_noremap:	    case CMD_dupmap:
+	case CMD_nmap:	    case CMD_nnoremap:	    case CMD_ndupmap:
+	case CMD_vmap:	    case CMD_vnoremap:	    case CMD_vdupmap:
+	case CMD_omap:	    case CMD_onoremap:	    case CMD_odupmap:
+	case CMD_imap:	    case CMD_inoremap:	    case CMD_idupmap:
+	case CMD_cmap:	    case CMD_cnoremap:	    case CMD_cdupmap:
 	    return set_context_in_map_cmd(xp, cmd, arg, forceit,
 							FALSE, FALSE, ea.cmdidx);
 	case CMD_unmap:
@@ -8054,7 +8054,8 @@
     mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
 
     switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
-						    eap->arg, mode, isabbrev))
+						    eap->arg, mode, isabbrev,
+						    (*cmdp == 'd' ? TRUE : FALSE)))
     {
 	case 1: EMSG(_(e_invarg));
 		break;
Index: src/ex_cmds.h
===================================================================
--- src/ex_cmds.h	(revision 1586)
+++ src/ex_cmds.h	(working copy)
@@ -235,6 +235,8 @@
 			BANG|TRLBAR|CMDWIN),
 EX(CMD_cmap,		"cmap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_cdupmap,		"cdupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_cmapclear,	"cmapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_cmenu,		"cmenu",	ex_menu,
@@ -445,6 +447,8 @@
 			BANG|RANGE|DFLALL|WHOLEFOLD|EXTRA|CMDWIN),
 EX(CMD_imap,		"imap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_idupmap,		"idupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_imapclear,	"imapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_imenu,		"imenu",	ex_menu,
@@ -539,6 +543,8 @@
 			BANG|EXTRA|TRLBAR|CMDWIN),
 EX(CMD_lmap,		"lmap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_ldupmap,		"ldupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_lmapclear,	"lmapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_lmake,		"lmake",	ex_make,
@@ -589,6 +595,8 @@
 			BANG|EXTRA|NOTRLCOM|TRLBAR|XFILE),
 EX(CMD_map,		"map",		ex_map,
 			BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_dupmap,		"dupmap",	ex_map,
+			BANG|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_mapclear,	"mapclear",	ex_mapclear,
 			EXTRA|BANG|TRLBAR|CMDWIN),
 EX(CMD_marks,		"marks",	do_marks,
@@ -625,6 +633,8 @@
 			BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR),
 EX(CMD_nmap,		"nmap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_ndupmap,		"ndupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_nmapclear,	"nmapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_nmenu,		"nmenu",	ex_menu,
@@ -657,6 +667,8 @@
 			BANG|TRLBAR|SBOXOK|CMDWIN),
 EX(CMD_omap,		"omap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_odupmap,		"odupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_omapclear,	"omapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_omenu,		"omenu",	ex_menu,
@@ -835,6 +847,8 @@
 			RANGE|WHOLEFOLD|EXTRA|CMDWIN),
 EX(CMD_smap,		"smap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_sdupmap,		"sdupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_smapclear,	"smapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_smenu,		"smenu",	ex_menu,
@@ -1015,6 +1029,8 @@
 			TRLBAR),
 EX(CMD_vmap,		"vmap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_vdupmap,		"vdupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_vmapclear,	"vmapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_vmenu,		"vmenu",	ex_menu,
@@ -1065,6 +1081,8 @@
 			BANG|TRLBAR),
 EX(CMD_xmap,		"xmap",		ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_xdupmap,		"xdupmap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_xmapclear,	"xmapclear",	ex_mapclear,
 			EXTRA|TRLBAR|CMDWIN),
 EX(CMD_xmenu,		"xmenu",	ex_menu,
Index: src/proto/getchar.pro
===================================================================
--- src/proto/getchar.pro	(revision 1586)
+++ src/proto/getchar.pro	(working copy)
@@ -47,7 +47,7 @@
 int inchar __ARGS((char_u *buf, int maxlen, long wait_time, int tb_change_cnt));
 int fix_input_buffer __ARGS((char_u *buf, int len, int script));
 int input_available __ARGS((void));
-int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev));
+int do_map __ARGS((int maptype, char_u *arg, int mode, int abbrev, int duplicate));
 int get_map_mode __ARGS((char_u **cmdp, int forceit));
 void map_clear __ARGS((char_u *cmdp, char_u *arg, int forceit, int abbr));
 void map_clear_int __ARGS((buf_T *buf, int mode, int local, int abbr));
Index: src/getchar.c
===================================================================
--- src/getchar.c	(revision 1586)
+++ src/getchar.c	(working copy)
@@ -3069,6 +3069,7 @@
  * unabbr {lhs}		    : remove abbreviation for {lhs}
  *
  * maptype: 0 for :map, 1 for :unmap, 2 for noremap.
+ * duplicate: TRUE for copy, FALSE: new map (used only when maptype: 0)
  *
  * arg is pointer to any arguments. Note: arg cannot be a read-only string,
  * it will be modified.
@@ -3095,14 +3096,14 @@
  *	  5 for entry not unique
  */
     int
-do_map(maptype, arg, mode, abbrev)
+do_map(maptype, arg, mode, abbrev, duplicate)
     int		maptype;
     char_u	*arg;
     int		mode;
     int		abbrev;		/* not a mapping but an abbreviation */
 {
     char_u	*keys;
-    mapblock_T	*mp, **mpp;
+    mapblock_T	*mp, **mpp, *mptodup = NULL;
     char_u	*rhs;
     char_u	*p;
     int		n;
@@ -3255,7 +3256,9 @@
 	if (STRICMP(rhs, "<nop>") == 0)	    /* "<Nop>" means nothing */
 	    rhs = (char_u *)"";
 	else
-	    rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special);
+	    // When duplicating, treat the rhs similar to keys.
+	    rhs = replace_termcodes(rhs, &arg_buf, duplicate ? TRUE : FALSE,
+		    TRUE, special);
     }
 
 #ifdef FEAT_FKMAP
@@ -3495,6 +3498,12 @@
 			    mpp = &(mp->m_next);
 			    continue;
 			}
+			else if (duplicate)
+			{
+			    mptodup = mp;
+			    did_it = TRUE;
+			    break; // What would be the purpose of continuing???
+			}
 			else if (unique)
 			{
 			    if (abbrev)
@@ -3559,6 +3568,11 @@
 	    retval = 2;			    /* no match */
 	goto theend;
     }
+    if (duplicate && !did_it)		    /* duplicate a non-existent entry */
+    {
+	retval = 2;
+	goto theend;
+    }
 
     if (!haskey || !hasarg)		    /* print entries */
     {
@@ -3576,11 +3590,12 @@
 	goto theend;			    /* listing finished */
     }
 
-    if (did_it)			/* have added the new entry already */
+    if (did_it && !duplicate)		/* have added the new entry already */
 	goto theend;
 
     /*
-     * Get here when adding a new entry to the maphash[] list or abbrlist.
+     * Get here when adding a new entry to the maphash[] list or abbrlist
+     * or when an existing map needs to be duplicated.
      */
     mp = (mapblock_T *)alloc((unsigned)sizeof(mapblock_T));
     if (mp == NULL)
@@ -3590,11 +3605,11 @@
     }
 
     /* If CTRL-C has been mapped, don't always use it for Interrupting */
-    if (*keys == Ctrl_C)
+    if (*keys == Ctrl_C || (duplicate && *rhs == Ctrl_C))
 	mapped_ctrl_c = TRUE;
 
-    mp->m_keys = vim_strsave(keys);
-    mp->m_str = vim_strsave(rhs);
+    mp->m_keys = vim_strsave(duplicate ? rhs : keys);
+    mp->m_str = vim_strsave(duplicate ? mptodup->m_str : rhs);
     if (mp->m_keys == NULL || mp->m_str == NULL)
     {
 	vim_free(mp->m_keys);
@@ -3604,13 +3619,26 @@
 	goto theend;
     }
     mp->m_keylen = (int)STRLEN(mp->m_keys);
-    mp->m_noremap = noremap;
-    mp->m_silent = silent;
-    mp->m_mode = mode;
+    if (!duplicate)
+    {
+	mp->m_noremap = noremap;
+	mp->m_silent = silent;
+	mp->m_mode = mode;
 #ifdef FEAT_EVAL
-    mp->m_expr = expr;
-    mp->m_script_ID = current_SID;
+	mp->m_expr = expr;
+	mp->m_script_ID = current_SID;
 #endif
+    }
+    else
+    {
+	mp->m_noremap = mptodup->m_noremap;
+	mp->m_silent = mptodup->m_silent;
+	mp->m_mode = mptodup->m_mode;
+#ifdef FEAT_EVAL
+	mp->m_expr = mptodup->m_expr;
+	mp->m_script_ID = mptodup->m_script_ID;
+#endif
+    }
 
     /* add the new entry in front of the abbrlist or maphash[] list */
     if (abbrev)
@@ -5154,7 +5182,7 @@
     s = vim_strsave(map);
     if (s != NULL)
     {
-	(void)do_map(0, s, mode, FALSE);
+	(void)do_map(0, s, mode, FALSE, FALSE);
 	vim_free(s);
     }
     p_cpo = cpo_save;
