mark.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:24k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8. /*
  9.  * mark.c: functions for setting marks and jumping to them
  10.  */
  11. #include "vim.h"
  12. /*
  13.  * This file contains routines to maintain and manipulate marks.
  14.  */
  15. /*
  16.  * If a named file mark's lnum is non-zero, it is valid.
  17.  * If a named file mark's fnum is non-zero, it is for an existing buffer,
  18.  * otherwise it is from .viminfo and namedfm_names[n] is the file name.
  19.  * There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing
  20.  * viminfo).
  21.  */
  22. #define EXTRA_MARKS 10 /* marks 0-9 */
  23. static struct filemark namedfm[NMARKS + EXTRA_MARKS]; /* marks with file nr */
  24. static char_u *namedfm_names[NMARKS + EXTRA_MARKS]; /* name for namedfm[] */
  25. static void show_one_mark __ARGS((int, char_u *, FPOS *, char_u *));
  26. static void cleanup_jumplist __ARGS((void));
  27. /*
  28.  * setmark(c) - set named mark 'c' at current cursor position
  29.  *
  30.  * Returns OK on success, FAIL if no room for mark or bad name given.
  31.  */
  32.     int
  33. setmark(c)
  34.     int c;
  35. {
  36.     int i;
  37.     if (c == ''' || c == '`')
  38.     {
  39. setpcmark();
  40. /* keep it even when the cursor doesn't move */
  41. curwin->w_prev_pcmark = curwin->w_pcmark;
  42. return OK;
  43.     }
  44.     if (c > 'z')     /* some islower() and isupper() cannot handle
  45. characters above 127 */
  46. return FAIL;
  47.     if (islower(c))
  48.     {
  49. i = c - 'a';
  50. curbuf->b_namedm[i] = curwin->w_cursor;
  51. return OK;
  52.     }
  53.     if (isupper(c))
  54.     {
  55. i = c - 'A';
  56. namedfm[i].mark = curwin->w_cursor;
  57. namedfm[i].fnum = curbuf->b_fnum;
  58. return OK;
  59.     }
  60.     return FAIL;
  61. }
  62. /*
  63.  * setpcmark() - set the previous context mark to the current position
  64.  *  and add it to the jump list
  65.  */
  66.     void
  67. setpcmark()
  68. {
  69.     int i;
  70. #ifdef ROTATE
  71.     struct filemark tempmark;
  72. #endif
  73.     /* for :global the mark is set only once */
  74.     if (global_busy)
  75. return;
  76.     curwin->w_prev_pcmark = curwin->w_pcmark;
  77.     curwin->w_pcmark = curwin->w_cursor;
  78. #ifdef ROTATE
  79.     /*
  80.      * If last used entry is not at the top, put it at the top by rotating
  81.      * the stack until it is (the newer entries will be at the bottom).
  82.      * Keep one entry (the last used one) at the top.
  83.      */
  84.     if (curwin->w_jumplistidx < curwin->w_jumplistlen)
  85. ++curwin->w_jumplistidx;
  86.     while (curwin->w_jumplistidx < curwin->w_jumplistlen)
  87.     {
  88. tempmark = curwin->w_jumplist[curwin->w_jumplistlen - 1];
  89. for (i = curwin->w_jumplistlen - 1; i > 0; --i)
  90.     curwin->w_jumplist[i] = curwin->w_jumplist[i - 1];
  91. curwin->w_jumplist[0] = tempmark;
  92. ++curwin->w_jumplistidx;
  93.     }
  94. #endif
  95.     /* If jumplist is full: remove oldest entry */
  96.     if (++curwin->w_jumplistlen > JUMPLISTSIZE)
  97.     {
  98. curwin->w_jumplistlen = JUMPLISTSIZE;
  99. for (i = 1; i < JUMPLISTSIZE; ++i)
  100.     curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
  101.     }
  102.     curwin->w_jumplistidx = curwin->w_jumplistlen - 1;
  103. #ifdef ARCHIE
  104.     /* Workaround for a bug in gcc 2.4.5 R2 on the Archimedes
  105.      * Should be fixed in 2.5.x.
  106.      */
  107.     curwin->w_jumplist[curwin->w_jumplistidx].mark.ptr = curwin->w_pcmark.ptr;
  108.     curwin->w_jumplist[curwin->w_jumplistidx].mark.col = curwin->w_pcmark.col;
  109. #else
  110.     curwin->w_jumplist[curwin->w_jumplistidx].mark = curwin->w_pcmark;
  111. #endif
  112.     curwin->w_jumplist[curwin->w_jumplistidx].fnum = curbuf->b_fnum;
  113.     ++curwin->w_jumplistidx;
  114. }
  115. /*
  116.  * checkpcmark() - To change context, call setpcmark(), then move the current
  117.  *    position to where ever, then call checkpcmark().  This
  118.  *    ensures that the previous context will only be changed if
  119.  *    the cursor moved to a different line. -- webb.
  120.  *    If pcmark was deleted (with "dG") the previous mark is
  121.  *    restored.
  122.  */
  123.     void
  124. checkpcmark()
  125. {
  126.     if (curwin->w_prev_pcmark.lnum != 0
  127.     && (equal(curwin->w_pcmark, curwin->w_cursor)
  128. || curwin->w_pcmark.lnum == 0))
  129.     {
  130. curwin->w_pcmark = curwin->w_prev_pcmark;
  131. curwin->w_prev_pcmark.lnum = 0; /* Show it has been checked */
  132.     }
  133. }
  134. /*
  135.  * move "count" positions in the jump list (count may be negative)
  136.  */
  137.     FPOS *
  138. movemark(count)
  139.     int count;
  140. {
  141.     FPOS *pos;
  142.     cleanup_jumplist();
  143.     if (curwin->w_jumplistlen == 0)     /* nothing to jump to */
  144. return (FPOS *)NULL;
  145.     if (curwin->w_jumplistidx + count < 0 ||
  146. curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
  147. return (FPOS *)NULL;
  148.     /*
  149.      * if first CTRL-O or CTRL-I command after a jump, add cursor position to
  150.      * list.  Careful: If there are duplicates (CTRL-O immidiately after
  151.      * starting Vim on a file), another entry may have been removed.
  152.      */
  153.     if (curwin->w_jumplistidx == curwin->w_jumplistlen)
  154.     {
  155. setpcmark();
  156. --curwin->w_jumplistidx; /* skip the new entry */
  157. if (curwin->w_jumplistidx + count < 0)
  158.     return (FPOS *)NULL;
  159.     }
  160.     curwin->w_jumplistidx += count;
  161. /* jump to other file */
  162.     if (curwin->w_jumplist[curwin->w_jumplistidx].fnum != curbuf->b_fnum)
  163.     {
  164. if (buflist_getfile(curwin->w_jumplist[curwin->w_jumplistidx].fnum,
  165.   curwin->w_jumplist[curwin->w_jumplistidx].mark.lnum,
  166.     0, FALSE) == FAIL)
  167.     return (FPOS *)NULL;
  168. curwin->w_cursor.col =
  169.    curwin->w_jumplist[curwin->w_jumplistidx].mark.col;
  170. pos = (FPOS *)-1;
  171.     }
  172.     else
  173. pos = &(curwin->w_jumplist[curwin->w_jumplistidx].mark);
  174.     return pos;
  175. }
  176. /*
  177.  * getmark(c) - find mark for char 'c'
  178.  *
  179.  * Return pointer to FPOS if found (caller needs to check lnum!)
  180.  *   NULL if there is no mark called 'c'.
  181.  *   -1 if mark is in other file (only if changefile is TRUE)
  182.  */
  183.     FPOS *
  184. getmark(c, changefile)
  185.     int c;
  186.     int changefile; /* allowed to edit another file */
  187. {
  188.     FPOS     *posp;
  189.     FPOS     *startp, *endp;
  190.     static  FPOS    pos_copy;
  191.     char_u     *p;
  192.     posp = NULL;
  193.     if (c > '~') /* check for islower()/isupper() */
  194. ;
  195.     else if (c == ''' || c == '`') /* previous context mark */
  196.     {
  197. pos_copy = curwin->w_pcmark; /* need to make a copy because */
  198. posp = &pos_copy; /*   w_pcmark may be changed soon */
  199.     }
  200.     else if (c == '"') /* to pos when leaving buffer */
  201. posp = &(curbuf->b_last_cursor);
  202.     else if (c == '[') /* to start of previous operator */
  203. posp = &(curbuf->b_op_start);
  204.     else if (c == ']') /* to end of previous operator */
  205. posp = &(curbuf->b_op_end);
  206.     else if (c == '<' || c == '>') /* start/end of visual area */
  207.     {
  208. startp = &curbuf->b_visual_start;
  209. endp = &curbuf->b_visual_end;
  210. if ((c == '<') == lt(*startp, *endp))
  211.     posp = startp;
  212. else
  213.     posp = endp;
  214. /*
  215.  * For Visual line mode, set mark at begin or end of line
  216.  */
  217. if (curbuf->b_visual_mode == 'V')
  218. {
  219.     pos_copy = *posp;
  220.     posp = &pos_copy;
  221.     if (c == '<')
  222. pos_copy.col = 0;
  223.     else
  224. pos_copy.col = MAXCOL;
  225. }
  226.     }
  227.     else if (islower(c)) /* normal named mark */
  228. posp = &(curbuf->b_namedm[c - 'a']);
  229.     else if (isupper(c) || vim_isdigit(c)) /* named file mark */
  230.     {
  231. if (vim_isdigit(c))
  232.     c = c - '0' + NMARKS;
  233. else
  234.     c -= 'A';
  235. posp = &(namedfm[c].mark);
  236. if (namedfm[c].fnum == 0 && namedfm_names[c] != NULL)
  237. {
  238.     /*
  239.      * First expand "~/" in the file name to the home directory.
  240.      * Try to shorten the file name.
  241.      */
  242.     expand_env(namedfm_names[c], NameBuff, MAXPATHL);
  243.     mch_dirname(IObuff, IOSIZE);
  244.     p = shorten_fname(NameBuff, IObuff);
  245.     /* buflist_new will call fmarks_check_names() */
  246.     (void)buflist_new(NameBuff, p, (linenr_t)1, FALSE);
  247. }
  248. if (namedfm[c].fnum != curbuf->b_fnum)     /* mark is in other file */
  249. {
  250.     if (namedfm[c].mark.lnum != 0 && changefile && namedfm[c].fnum)
  251.     {
  252. if (buflist_getfile(namedfm[c].fnum,
  253.      namedfm[c].mark.lnum, GETF_SETMARK, FALSE) == OK)
  254. {
  255.     curwin->w_cursor.col = namedfm[c].mark.col;
  256.     return (FPOS *)-1;
  257. }
  258.     }
  259.     posp = &pos_copy; /* mark exists, but is not valid in
  260.     current buffer */
  261.     pos_copy.lnum = 0;
  262. }
  263.     }
  264.     return posp;
  265. }
  266. /*
  267.  * Check all file marks for a name that matches the file name in buf.
  268.  * May replace the name with an fnum.
  269.  */
  270.     void
  271. fmarks_check_names(buf)
  272.     BUF     *buf;
  273. {
  274.     char_u *name;
  275.     int i;
  276.     if (buf->b_ffname == NULL)
  277. return;
  278.     name = home_replace_save(buf, buf->b_ffname);
  279.     if (name == NULL)
  280. return;
  281.     for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
  282.     {
  283. if (namedfm[i].fnum == 0 && namedfm_names[i] != NULL &&
  284. fnamecmp(name, namedfm_names[i]) == 0)
  285. {
  286.     namedfm[i].fnum = buf->b_fnum;
  287.     vim_free(namedfm_names[i]);
  288.     namedfm_names[i] = NULL;
  289. }
  290.     }
  291.     vim_free(name);
  292. }
  293. /*
  294.  * Check a if a position from a mark is valid.
  295.  * Give and error message and return FAIL if not.
  296.  */
  297.     int
  298. check_mark(pos)
  299.     FPOS    *pos;
  300. {
  301.     if (pos == NULL)
  302.     {
  303. emsg(e_umark);
  304. return FAIL;
  305.     }
  306.     if (pos->lnum == 0)
  307.     {
  308. emsg(e_marknotset);
  309. return FAIL;
  310.     }
  311.     if (pos->lnum > curbuf->b_ml.ml_line_count)
  312.     {
  313. emsg(e_markinval);
  314. return FAIL;
  315.     }
  316.     return OK;
  317. }
  318. /*
  319.  * clrallmarks() - clear all marks in the buffer 'buf'
  320.  *
  321.  * Used mainly when trashing the entire buffer during ":e" type commands
  322.  */
  323.     void
  324. clrallmarks(buf)
  325.     BUF     *buf;
  326. {
  327.     static int i = -1;
  328.     if (i == -1) /* first call ever: initialize */
  329. for (i = 0; i < NMARKS + 1; i++)
  330. {
  331.     namedfm[i].mark.lnum = 0;
  332.     namedfm_names[i] = NULL;
  333. }
  334.     for (i = 0; i < NMARKS; i++)
  335. buf->b_namedm[i].lnum = 0;
  336.     buf->b_op_start.lnum = 0; /* start/end op mark cleared */
  337.     buf->b_op_end.lnum = 0;
  338.     buf->b_last_cursor.lnum = 1; /* '" mark cleared */
  339.     buf->b_last_cursor.col = 0;
  340. }
  341. /*
  342.  * Get name of file from a filemark.
  343.  * Returns an allocated string.
  344.  */
  345.     char_u *
  346. fm_getname(fmark)
  347.     struct filemark *fmark;
  348. {
  349.     if (fmark->fnum != curbuf->b_fnum)     /* not current file */
  350. return buflist_nr2name(fmark->fnum, FALSE, TRUE);
  351.     return vim_strsave((char_u *)"-current-");
  352. }
  353. /*
  354.  * print the marks
  355.  */
  356.     void
  357. do_marks(arg)
  358.     char_u *arg;
  359. {
  360.     int i;
  361.     char_u *name;
  362.     if (arg != NULL && *arg == NUL)
  363. arg = NULL;
  364.     show_one_mark(''', arg, &curwin->w_pcmark, NULL);
  365.     for (i = 0; i < NMARKS; ++i)
  366. show_one_mark(i + 'a', arg, &curbuf->b_namedm[i], NULL);
  367.     for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
  368.     {
  369. name = namedfm[i].fnum ? fm_getname(&namedfm[i]) : namedfm_names[i];
  370. if (name != NULL)
  371. {
  372.     show_one_mark(i >= NMARKS ? i - NMARKS + '0' : i + 'A',
  373.  arg, &namedfm[i].mark, name);
  374.     if (namedfm[i].fnum)
  375. vim_free(name);
  376. }
  377.     }
  378.     show_one_mark('"', arg, &curbuf->b_last_cursor, NULL);
  379.     show_one_mark('[', arg, &curbuf->b_op_start, NULL);
  380.     show_one_mark(']', arg, &curbuf->b_op_end, NULL);
  381.     show_one_mark('<', arg, &curbuf->b_visual_start, NULL);
  382.     show_one_mark('>', arg, &curbuf->b_visual_end, NULL);
  383.     show_one_mark(-1, arg, NULL, NULL);
  384. }
  385.     static void
  386. show_one_mark(c, arg, p, name)
  387.     int     c;
  388.     char_u  *arg;
  389.     FPOS    *p;
  390.     char_u  *name;
  391. {
  392.     static int     did_title = FALSE;
  393.     if (c == -1)     /* finish up */
  394.     {
  395. if (did_title)
  396.     did_title = FALSE;
  397. else
  398. {
  399.     if (arg == NULL)
  400. MSG("No marks set");
  401.     else
  402. EMSG2("No marks matching "%s"", arg);
  403. }
  404.     }
  405.     /* don't output anything if 'q' typed at --more-- prompt */
  406.     else if (!got_int && (arg == NULL || vim_strchr(arg, c) != NULL) &&
  407.  p->lnum != 0)
  408.     {
  409. if (!did_title)
  410. {
  411.     /* Highlight title */
  412.     MSG_PUTS_TITLE("nmark line  col file");
  413.     did_title = TRUE;
  414. }
  415. msg_putchar('n');
  416. if (!got_int)
  417. {
  418.     sprintf((char *)IObuff, " %c %5ld  %3d  ", c, p->lnum, p->col);
  419.     if (name != NULL)
  420. STRCAT(IObuff, name);
  421.     msg_outtrans(IObuff);
  422. }
  423. out_flush();     /* show one line at a time */
  424.     }
  425. }
  426. /*
  427.  * print the jumplist
  428.  */
  429.     void
  430. do_jumps()
  431. {
  432.     int i;
  433.     char_u *name;
  434.     cleanup_jumplist();
  435.     /* Highlight title */
  436.     MSG_PUTS_TITLE("n jump line  file");
  437.     for (i = 0; i < curwin->w_jumplistlen; ++i)
  438.     {
  439. if (curwin->w_jumplist[i].mark.lnum != 0)
  440. {
  441.     name = fm_getname(&curwin->w_jumplist[i]);
  442.     if (name == NULL)     /* file name not available */
  443. continue;
  444.     msg_putchar('n');
  445.     sprintf((char *)IObuff, "%c %2d %5ld  %s",
  446. i == curwin->w_jumplistidx ? '>' : ' ',
  447. i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
  448.   : curwin->w_jumplistidx - i,
  449. curwin->w_jumplist[i].mark.lnum,
  450. name);
  451.     msg_outtrans(IObuff);
  452.     vim_free(name);
  453. }
  454. out_flush();
  455.     }
  456.     if (curwin->w_jumplistidx == curwin->w_jumplistlen)
  457. MSG_PUTS("n>");
  458. }
  459. /*
  460.  * adjust marks between line1 and line2 (inclusive) to move 'amount' lines
  461.  * If 'amount' is MAXLNUM the mark is made invalid.
  462.  * If 'amount_after' is non-zero adjust marks after line 2.
  463.  */
  464. #define one_adjust(add) 
  465.     { 
  466. lp = add; 
  467. if (*lp >= line1 && *lp <= line2) 
  468.     if (amount == MAXLNUM) 
  469. *lp = 0; 
  470.     else 
  471. *lp += amount; 
  472. else if (amount_after && *lp > line2) 
  473.     *lp += amount_after; 
  474.     }
  475. /* don't delete the line, just put at first deleted line */
  476. #define one_adjust_nodel(add) 
  477.     { 
  478. lp = add; 
  479. if (*lp >= line1 && *lp <= line2) 
  480.     if (amount == MAXLNUM) 
  481. *lp = line1; 
  482.     else 
  483. *lp += amount; 
  484. else if (amount_after && *lp > line2) 
  485.     *lp += amount_after; 
  486.     }
  487.     void
  488. mark_adjust(line1, line2, amount, amount_after)
  489.     linenr_t line1;
  490.     linenr_t line2;
  491.     long amount;
  492.     long amount_after;
  493. {
  494.     int i;
  495.     int fnum = curbuf->b_fnum;
  496.     linenr_t *lp;
  497.     WIN *win;
  498.     if (line2 < line1 && amount_after == 0L)     /* nothing to do */
  499. return;
  500. /* named marks, lower case and upper case */
  501.     for (i = 0; i < NMARKS; i++)
  502.     {
  503. one_adjust(&(curbuf->b_namedm[i].lnum));
  504. if (namedfm[i].fnum == fnum)
  505.     one_adjust(&(namedfm[i].mark.lnum));
  506.     }
  507.     for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
  508.     {
  509. if (namedfm[i].fnum == fnum)
  510.     one_adjust(&(namedfm[i].mark.lnum));
  511.     }
  512. /* previous context mark */
  513.     one_adjust(&(curwin->w_pcmark.lnum));
  514. /* previous pcmark */
  515.     one_adjust(&(curwin->w_prev_pcmark.lnum));
  516. /* Visual area */
  517.     one_adjust_nodel(&(curbuf->b_visual_start.lnum));
  518.     one_adjust_nodel(&(curbuf->b_visual_end.lnum));
  519. /* marks in the tag stack */
  520.     for (win = firstwin; win != NULL; win = win->w_next)
  521. if (win->w_buffer == curbuf)
  522.     for (i = 0; i < win->w_tagstacklen; i++)
  523. if (win->w_tagstack[i].fmark.fnum == fnum)
  524.     one_adjust_nodel(&(win->w_tagstack[i].fmark.mark.lnum));
  525. #ifdef QUICKFIX
  526. /* quickfix marks */
  527.     qf_mark_adjust(line1, line2, amount, amount_after);
  528. #endif
  529. /* jumplist marks */
  530.     for (win = firstwin; win != NULL; win = win->w_next)
  531.     {
  532. /*
  533.  * When deleting lines, this may create duplicate marks in the
  534.  * jumplist. They will be removed later.
  535.  */
  536. for (i = 0; i < win->w_jumplistlen; ++i)
  537.     if (win->w_jumplist[i].fnum == fnum)
  538. one_adjust_nodel(&(win->w_jumplist[i].mark.lnum));
  539. /*
  540.  * also adjust the line at the top of the window and the cursor
  541.  * position for windows with the same buffer.
  542.  */
  543. if (win != curwin && win->w_buffer == curbuf)
  544. {
  545.     if (win->w_topline >= line1 && win->w_topline <= line2)
  546.     {
  547. if (amount == MAXLNUM)     /* topline is deleted */
  548. {
  549.     if (line1 <= 1)
  550. win->w_topline = 1;
  551.     else
  552. win->w_topline = line1 - 1;
  553. }
  554. else /* keep topline on the same line */
  555.     win->w_topline += amount;
  556.     }
  557.     else if (amount_after && win->w_topline > line2)
  558. win->w_topline += amount_after;
  559.     if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
  560.     {
  561. if (amount == MAXLNUM)     /* line with cursor is deleted */
  562. {
  563.     if (line1 <= 1)
  564. win->w_cursor.lnum = 1;
  565.     else
  566. win->w_cursor.lnum = line1 - 1;
  567.     win->w_cursor.col = 0;
  568. }
  569. else /* keep cursor on the same line */
  570.     win->w_cursor.lnum += amount;
  571.     }
  572.     else if (amount_after && win->w_cursor.lnum > line2)
  573. win->w_cursor.lnum += amount_after;
  574. }
  575.     }
  576. }
  577. /*
  578.  * When deleting lines, this may create duplicate marks in the
  579.  * jumplist. They will be removed here for the current window.
  580.  */
  581.     static void
  582. cleanup_jumplist()
  583. {
  584.     int     i;
  585.     int     from, to;
  586.     to = 0;
  587.     for (from = 0; from < curwin->w_jumplistlen; ++from)
  588.     {
  589. if (curwin->w_jumplistidx == from)
  590.     curwin->w_jumplistidx = to;
  591. for (i = from + 1; i < curwin->w_jumplistlen; ++i)
  592.     if (curwin->w_jumplist[i].fnum == curwin->w_jumplist[from].fnum &&
  593. curwin->w_jumplist[i].mark.lnum ==
  594.    curwin->w_jumplist[from].mark.lnum)
  595. break;
  596. if (i >= curwin->w_jumplistlen)     /* no duplicate */
  597.     curwin->w_jumplist[to++] = curwin->w_jumplist[from];
  598.     }
  599.     if (curwin->w_jumplistidx == curwin->w_jumplistlen)
  600. curwin->w_jumplistidx = to;
  601.     curwin->w_jumplistlen = to;
  602. }
  603.     void
  604. set_last_cursor(win)
  605.     WIN     *win;
  606. {
  607.     win->w_buffer->b_last_cursor = win->w_cursor;
  608. }
  609. #ifdef VIMINFO
  610.     int
  611. read_viminfo_filemark(line, fp, force)
  612.     char_u  *line;
  613.     FILE    *fp;
  614.     int     force;
  615. {
  616.     int     idx;
  617.     char_u  *str;
  618.     /* We only get here (hopefully) if line[0] == ''' */
  619.     str = line + 1;
  620.     if (*str > 127 || (!isdigit(*str) && !isupper(*str)))
  621.     {
  622. if (viminfo_error("Illegal file mark name", line))
  623.     return TRUE; /* Too many errors, pretend end-of-file */
  624.     }
  625.     else
  626.     {
  627. if (isdigit(*str))
  628.     idx = *str - '0' + NMARKS;
  629. else
  630.     idx = *str - 'A';
  631. if (namedfm[idx].mark.lnum == 0 || force)
  632. {
  633.     str = skipwhite(str + 1);
  634.     namedfm[idx].mark.lnum = getdigits(&str);
  635.     str = skipwhite(str);
  636.     namedfm[idx].mark.col = getdigits(&str);
  637.     str = skipwhite(str);
  638.     viminfo_readstring(line);
  639.     namedfm_names[idx] = vim_strsave(str);
  640. }
  641.     }
  642.     return vim_fgets(line, LSIZE, fp);
  643. }
  644.     void
  645. write_viminfo_filemarks(fp)
  646.     FILE    *fp;
  647. {
  648.     int     i;
  649.     char_u  *name;
  650.     if (get_viminfo_parameter(''') == 0)
  651. return;
  652.     fprintf(fp, "n# File marks:n");
  653.     /*
  654.      * Find a mark that is the same file and position as the cursor.
  655.      * That one, or else the last one is deleted.
  656.      * Move '0 to '1, '1 to '2, etc. until the matching one or '9
  657.      * Set '0 mark to current cursor position.
  658.      */
  659.     if (curbuf->b_ffname != NULL && !removable(curbuf->b_ffname))
  660.     {
  661. name = buflist_nr2name(curbuf->b_fnum, TRUE, FALSE);
  662. for (i = NMARKS; i < NMARKS + EXTRA_MARKS - 1; ++i)
  663.     if (namedfm[i].mark.lnum == curwin->w_cursor.lnum
  664.     && (namedfm_names[i] == NULL
  665.     ? namedfm[i].fnum == curbuf->b_fnum
  666.     : (name != NULL
  667.     && STRCMP(name, namedfm_names[i]) == 0)))
  668. break;
  669. vim_free(name);
  670. vim_free(namedfm_names[i]);
  671. for ( ; i > NMARKS; --i)
  672. {
  673.     namedfm[i] = namedfm[i - 1];
  674.     namedfm_names[i] = namedfm_names[i - 1];
  675. }
  676. namedfm[NMARKS].mark = curwin->w_cursor;
  677. namedfm[NMARKS].fnum = curbuf->b_fnum;
  678. namedfm_names[NMARKS] = NULL;
  679.     }
  680.     for (i = 0; i < NMARKS + EXTRA_MARKS; i++)
  681.     {
  682. if (namedfm[i].mark.lnum == 0) /* not set */
  683.     continue;
  684. if (namedfm[i].fnum) /* there is a buffer */
  685.     name = buflist_nr2name(namedfm[i].fnum, TRUE, FALSE);
  686. else
  687.     name = namedfm_names[i]; /* use name from .viminfo */
  688. if (name == NULL)
  689.     continue;
  690. fprintf(fp, "'%c  %ld  %ld  %sn",
  691.     i < NMARKS ? i + 'A' : i - NMARKS + '0',
  692.     (long)namedfm[i].mark.lnum,
  693.     (long)namedfm[i].mark.col,
  694.     name);
  695. if (namedfm[i].fnum)
  696.     vim_free(name);
  697.     }
  698. }
  699. /*
  700.  * Return TRUE if "name" is on removable media (depending on 'viminfo').
  701.  */
  702.     int
  703. removable(name)
  704.     char_u  *name;
  705. {
  706.     char_u  *p;
  707.     char_u  part[51];
  708.     int     retval = FALSE;
  709.     name = home_replace_save(NULL, name);
  710.     if (name != NULL)
  711.     {
  712. for (p = p_viminfo; *p; )
  713. {
  714.     copy_option_part(&p, part, 51, ", ");
  715.     if (part[0] == 'r'
  716.    && STRNICMP(part + 1, name, STRLEN(part + 1)) == 0)
  717.     {
  718. retval = TRUE;
  719. break;
  720.     }
  721. }
  722. vim_free(name);
  723.     }
  724.     return retval;
  725. }
  726. /*
  727.  * Write all the named marks for all buffers.
  728.  * Return the number of buffers for which marks have been written.
  729.  */
  730.     int
  731. write_viminfo_marks(fp_out)
  732.     FILE    *fp_out;
  733. {
  734.     int     count;
  735.     BUF     *buf;
  736.     WIN     *win;
  737.     int     is_mark_set;
  738.     int     i;
  739.     /*
  740.      * Set b_last_cursor for the all buffers that have a window.
  741.      */
  742.     for (win = firstwin; win != NULL; win = win->w_next)
  743. set_last_cursor(win);
  744.     fprintf(fp_out, "n# History of marks within files (newest to oldest):n");
  745.     count = 0;
  746.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  747.     {
  748. /*
  749.  * Only write something if buffer has been loaded and at least one
  750.  * mark is set.
  751.  */
  752. if (buf->b_marks_read)
  753. {
  754.     if (buf->b_last_cursor.lnum != 0)
  755. is_mark_set = TRUE;
  756.     else
  757.     {
  758. is_mark_set = FALSE;
  759. for (i = 0; i < NMARKS; i++)
  760.     if (buf->b_namedm[i].lnum != 0)
  761.     {
  762. is_mark_set = TRUE;
  763. break;
  764.     }
  765.     }
  766.     if (is_mark_set && buf->b_ffname != NULL &&
  767.  buf->b_ffname[0] != NUL && !removable(buf->b_ffname))
  768.     {
  769. home_replace(NULL, buf->b_ffname, IObuff, IOSIZE, TRUE);
  770. fprintf(fp_out, "n> %sn", (char *)IObuff);
  771. if (buf->b_last_cursor.lnum != 0)
  772.     fprintf(fp_out, "t"t%ldt%dn",
  773.     buf->b_last_cursor.lnum, buf->b_last_cursor.col);
  774. for (i = 0; i < NMARKS; i++)
  775.     if (buf->b_namedm[i].lnum != 0)
  776. fprintf(fp_out, "t%ct%ldt%dn", 'a' + i,
  777. buf->b_namedm[i].lnum, buf->b_namedm[i].col);
  778. count++;
  779.     }
  780. }
  781.     }
  782.     return count;
  783. }
  784. /*
  785.  * Handle marks in the viminfo file:
  786.  * fp_out == NULL   read marks for current buffer only
  787.  * fp_out != NULL   copy marks for buffers not in buffer list
  788.  */
  789.     void
  790. copy_viminfo_marks(line, fp_in, fp_out, count, eof)
  791.     char_u *line;
  792.     FILE *fp_in;
  793.     FILE *fp_out;
  794.     int count;
  795.     int eof;
  796. {
  797.     BUF *buf;
  798.     int num_marked_files;
  799.     char_u save_char;
  800.     int load_marks;
  801.     int copy_marks_out;
  802.     char_u *str;
  803.     int i;
  804.     char_u *p;
  805.     char_u *name_buf;
  806.     long lnum;
  807.     int col;
  808.     if ((name_buf = alloc(LSIZE)) == NULL)
  809. return;
  810.     num_marked_files = get_viminfo_parameter(''');
  811.     while (!eof && (count < num_marked_files || fp_out == NULL))
  812.     {
  813. if (line[0] != '>')
  814. {
  815.     if (line[0] != 'n' && line[0] != 'r' && line[0] != '#')
  816.     {
  817. if (viminfo_error("Missing '>'", line))
  818.     break; /* too many errors, return now */
  819.     }
  820.     eof = vim_fgets(line, LSIZE, fp_in);
  821.     continue; /* Skip this dud line */
  822. }
  823. /*
  824.  * Find file name, set str to start.
  825.  * Ignore leading and trailing white space.
  826.  */
  827. str = skipwhite(line + 1);
  828. p = str + STRLEN(str);
  829. while (p != str && (*p == NUL || vim_isspace(*p)))
  830.     p--;
  831. if (*p)
  832.     p++;
  833. save_char = *p;
  834. *p = NUL;
  835. /*
  836.  * If fp_out == NULL, load marks for current buffer.
  837.  * If fp_out != NULL, copy marks for buffers not in buflist.
  838.  */
  839. load_marks = copy_marks_out = FALSE;
  840. if (fp_out == NULL)
  841. {
  842.     if (curbuf->b_ffname != NULL)
  843.     {
  844. home_replace(NULL, curbuf->b_ffname, name_buf, LSIZE, TRUE);
  845. if (fnamecmp(str, name_buf) == 0)
  846.     load_marks = TRUE;
  847.     }
  848. }
  849. else /* fp_out != NULL */
  850. {
  851.     /* This is slow if there are many buffers!! */
  852.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  853. if (buf->b_ffname != NULL)
  854. {
  855.     home_replace(NULL, buf->b_ffname, name_buf, LSIZE, TRUE);
  856.     if (fnamecmp(str, name_buf) == 0)
  857. break;
  858. }
  859.     /*
  860.      * copy marks if the buffer has not been loaded
  861.      */
  862.     if (buf == NULL || !buf->b_marks_read)
  863.     {
  864. copy_marks_out = TRUE;
  865. *p = save_char;
  866. fputs("n", fp_out);
  867. fputs((char *)line, fp_out);
  868. count++;
  869.     }
  870. }
  871. while (!(eof = vim_fgets(line, LSIZE, fp_in)) && line[0] == TAB)
  872. {
  873.     if (load_marks)
  874.     {
  875. if (line[1] != NUL)
  876.     sscanf((char *)line + 2, "%ld %d", &lnum, &col);
  877. if (line[1] == '"')
  878. {
  879.     curbuf->b_last_cursor.lnum = lnum;
  880.     curbuf->b_last_cursor.col = col;
  881. }
  882. else if ((i = line[1] - 'a') >= 0 && i < NMARKS)
  883. {
  884.     curbuf->b_namedm[i].lnum = lnum;
  885.     curbuf->b_namedm[i].col = col;
  886. }
  887.     }
  888.     else if (copy_marks_out)
  889. fputs((char *)line, fp_out);
  890. }
  891. if (load_marks)
  892.     break;
  893.     }
  894.     vim_free(name_buf);
  895. }
  896. #endif /* VIMINFO */