home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / common / log.c < prev    next >
C/C++ Source or Header  |  1996-06-12  |  16KB  |  718 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)log.c    10.8 (Berkeley) 3/6/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18. #include <sys/stat.h>
  19.  
  20. #include <bitstring.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <limits.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. #include "common.h"
  29.  
  30. /*
  31.  * The log consists of records, each containing a type byte and a variable
  32.  * length byte string, as follows:
  33.  *
  34.  *    LOG_CURSOR_INIT        MARK
  35.  *    LOG_CURSOR_END        MARK
  36.  *    LOG_LINE_APPEND     recno_t        char *
  37.  *    LOG_LINE_DELETE        recno_t        char *
  38.  *    LOG_LINE_INSERT        recno_t        char *
  39.  *    LOG_LINE_RESET_F    recno_t        char *
  40.  *    LOG_LINE_RESET_B    recno_t        char *
  41.  *    LOG_MARK        LMARK
  42.  *
  43.  * We do before image physical logging.  This means that the editor layer
  44.  * MAY NOT modify records in place, even if simply deleting or overwriting
  45.  * characters.  Since the smallest unit of logging is a line, we're using
  46.  * up lots of space.  This may eventually have to be reduced, probably by
  47.  * doing logical logging, which is a much cooler database phrase.
  48.  *
  49.  * The implementation of the historic vi 'u' command, using roll-forward and
  50.  * roll-back, is simple.  Each set of changes has a LOG_CURSOR_INIT record,
  51.  * followed by a number of other records, followed by a LOG_CURSOR_END record.
  52.  * LOG_LINE_RESET records come in pairs.  The first is a LOG_LINE_RESET_B
  53.  * record, and is the line before the change.  The second is LOG_LINE_RESET_F,
  54.  * and is the line after the change.  Roll-back is done by backing up to the
  55.  * first LOG_CURSOR_INIT record before a change.  Roll-forward is done in a
  56.  * similar fashion.
  57.  *
  58.  * The 'U' command is implemented by rolling backward to a LOG_CURSOR_END
  59.  * record for a line different from the current one.  It should be noted that
  60.  * this means that a subsequent 'u' command will make a change based on the
  61.  * new position of the log's cursor.  This is okay, and, in fact, historic vi
  62.  * behaved that way.
  63.  */
  64.  
  65. static int    log_cursor1 __P((SCR *, int));
  66. static void    log_err __P((SCR *, char *, int));
  67. #if defined(DEBUG) && 0
  68. static void    log_trace __P((SCR *, char *, recno_t, u_char *));
  69. #endif
  70.  
  71. /* Try and restart the log on failure, i.e. if we run out of memory. */
  72. #define    LOG_ERR {                            \
  73.     log_err(sp, __FILE__, __LINE__);                \
  74.     return (1);                            \
  75. }
  76.  
  77. /*
  78.  * log_init --
  79.  *    Initialize the logging subsystem.
  80.  *
  81.  * PUBLIC: int log_init __P((SCR *, EXF *));
  82.  */
  83. int
  84. log_init(sp, ep)
  85.     SCR *sp;
  86.     EXF *ep;
  87. {
  88.     /*
  89.      * !!!
  90.      * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
  91.      *
  92.      * Initialize the buffer.  The logging subsystem has its own
  93.      * buffers because the global ones are almost by definition
  94.      * going to be in use when the log runs.
  95.      */
  96.     ep->l_lp = NULL;
  97.     ep->l_len = 0;
  98.     ep->l_cursor.lno = 1;        /* XXX Any valid recno. */
  99.     ep->l_cursor.cno = 0;
  100.     ep->l_high = ep->l_cur = 1;
  101.  
  102.     ep->log = dbopen(NULL, O_CREAT | O_NONBLOCK | O_RDWR,
  103.         S_IRUSR | S_IWUSR, DB_RECNO, NULL);
  104.     if (ep->log == NULL) {
  105.         msgq(sp, M_SYSERR, "009|Log file");
  106.         F_SET(ep, F_NOLOG);
  107.         return (1);
  108.     }
  109.  
  110.     return (0);
  111. }
  112.  
  113. /*
  114.  * log_end --
  115.  *    Close the logging subsystem.
  116.  *
  117.  * PUBLIC: int log_end __P((SCR *, EXF *));
  118.  */
  119. int
  120. log_end(sp, ep)
  121.     SCR *sp;
  122.     EXF *ep;
  123. {
  124.     /*
  125.      * !!!
  126.      * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
  127.      */
  128.     if (ep->log != NULL) {
  129.         (void)(ep->log->close)(ep->log);
  130.         ep->log = NULL;
  131.     }
  132.     if (ep->l_lp != NULL) {
  133.         free(ep->l_lp);
  134.         ep->l_lp = NULL;
  135.     }
  136.     ep->l_len = 0;
  137.     ep->l_cursor.lno = 1;        /* XXX Any valid recno. */
  138.     ep->l_cursor.cno = 0;
  139.     ep->l_high = ep->l_cur = 1;
  140.     return (0);
  141. }
  142.  
  143. /*
  144.  * log_cursor --
  145.  *    Log the current cursor position, starting an event.
  146.  *
  147.  * PUBLIC: int log_cursor __P((SCR *));
  148.  */
  149. int
  150. log_cursor(sp)
  151.     SCR *sp;
  152. {
  153.     EXF *ep;
  154.  
  155.     ep = sp->ep;
  156.     if (F_ISSET(ep, F_NOLOG))
  157.         return (0);
  158.  
  159.     /*
  160.      * If any changes were made since the last cursor init,
  161.      * put out the ending cursor record.
  162.      */
  163.     if (ep->l_cursor.lno == OOBLNO) {
  164.         ep->l_cursor.lno = sp->lno;
  165.         ep->l_cursor.cno = sp->cno;
  166.         return (log_cursor1(sp, LOG_CURSOR_END));
  167.     }
  168.     ep->l_cursor.lno = sp->lno;
  169.     ep->l_cursor.cno = sp->cno;
  170.     return (0);
  171. }
  172.  
  173. /*
  174.  * log_cursor1 --
  175.  *    Actually push a cursor record out.
  176.  */
  177. static int
  178. log_cursor1(sp, type)
  179.     SCR *sp;
  180.     int type;
  181. {
  182.     DBT data, key;
  183.     EXF *ep;
  184.  
  185.     ep = sp->ep;
  186.     BINC_RET(sp, ep->l_lp, ep->l_len, sizeof(u_char) + sizeof(MARK));
  187.     ep->l_lp[0] = type;
  188.     memmove(ep->l_lp + sizeof(u_char), &ep->l_cursor, sizeof(MARK));
  189.  
  190.     key.data = &ep->l_cur;
  191.     key.size = sizeof(recno_t);
  192.     data.data = ep->l_lp;
  193.     data.size = sizeof(u_char) + sizeof(MARK);
  194.     if (ep->log->put(ep->log, &key, &data, 0) == -1)
  195.         LOG_ERR;
  196.  
  197. #if defined(DEBUG) && 0
  198.     TRACE(sp, "%lu: %s: %u/%u\n", ep->l_cur,
  199.         type == LOG_CURSOR_INIT ? "log_cursor_init" : "log_cursor_end",
  200.         sp->lno, sp->cno);
  201. #endif
  202.     /* Reset high water mark. */
  203.     ep->l_high = ++ep->l_cur;
  204.  
  205.     return (0);
  206. }
  207.  
  208. /*
  209.  * log_line --
  210.  *    Log a line change.
  211.  *
  212.  * PUBLIC: int log_line __P((SCR *, recno_t, u_int));
  213.  */
  214. int
  215. log_line(sp, lno, action)
  216.     SCR *sp;
  217.     recno_t lno;
  218.     u_int action;
  219. {
  220.     DBT data, key;
  221.     EXF *ep;
  222.     size_t len;
  223.     char *lp;
  224.  
  225.     ep = sp->ep;
  226.     if (F_ISSET(ep, F_NOLOG))
  227.         return (0);
  228.  
  229.     /*
  230.      * XXX
  231.      *
  232.      * Kluge for vi.  Clear the EXF undo flag so that the
  233.      * next 'u' command does a roll-back, regardless.
  234.      */
  235.     F_CLR(ep, F_UNDO);
  236.  
  237.     /* Put out one initial cursor record per set of changes. */
  238.     if (ep->l_cursor.lno != OOBLNO) {
  239.         if (log_cursor1(sp, LOG_CURSOR_INIT))
  240.             return (1);
  241.         ep->l_cursor.lno = OOBLNO;
  242.     }
  243.  
  244.     /*
  245.      * Put out the changes.  If it's a LOG_LINE_RESET_B call, it's a
  246.      * special case, avoid the caches.  Also, if it fails and it's
  247.      * line 1, it just means that the user started with an empty file,
  248.      * so fake an empty length line.
  249.      */
  250.     if (action == LOG_LINE_RESET_B) {
  251.         if (db_get(sp, lno, DBG_NOCACHE, &lp, &len)) {
  252.             if (lno != 1) {
  253.                 db_err(sp, lno);
  254.                 return (1);
  255.             }
  256.             len = 0;
  257.             lp = "";
  258.         }
  259.     } else
  260.         if (db_get(sp, lno, DBG_FATAL, &lp, &len))
  261.             return (1);
  262.     BINC_RET(sp,
  263.         ep->l_lp, ep->l_len, len + sizeof(u_char) + sizeof(recno_t));
  264.     ep->l_lp[0] = action;
  265.     memmove(ep->l_lp + sizeof(u_char), &lno, sizeof(recno_t));
  266.     memmove(ep->l_lp + sizeof(u_char) + sizeof(recno_t), lp, len);
  267.  
  268.     key.data = &ep->l_cur;
  269.     key.size = sizeof(recno_t);
  270.     data.data = ep->l_lp;
  271.     data.size = len + sizeof(u_char) + sizeof(recno_t);
  272.     if (ep->log->put(ep->log, &key, &data, 0) == -1)
  273.         LOG_ERR;
  274.  
  275. #if defined(DEBUG) && 0
  276.     switch (action) {
  277.     case LOG_LINE_APPEND:
  278.         TRACE(sp, "%u: log_line: append: %lu {%u}\n",
  279.             ep->l_cur, lno, len);
  280.         break;
  281.     case LOG_LINE_DELETE:
  282.         TRACE(sp, "%lu: log_line: delete: %lu {%u}\n",
  283.             ep->l_cur, lno, len);
  284.         break;
  285.     case LOG_LINE_INSERT:
  286.         TRACE(sp, "%lu: log_line: insert: %lu {%u}\n",
  287.             ep->l_cur, lno, len);
  288.         break;
  289.     case LOG_LINE_RESET_F:
  290.         TRACE(sp, "%lu: log_line: reset_f: %lu {%u}\n",
  291.             ep->l_cur, lno, len);
  292.         break;
  293.     case LOG_LINE_RESET_B:
  294.         TRACE(sp, "%lu: log_line: reset_b: %lu {%u}\n",
  295.             ep->l_cur, lno, len);
  296.         break;
  297.     }
  298. #endif
  299.     /* Reset high water mark. */
  300.     ep->l_high = ++ep->l_cur;
  301.  
  302.     return (0);
  303. }
  304.  
  305. /*
  306.  * log_mark --
  307.  *    Log a mark position.  For the log to work, we assume that there
  308.  *    aren't any operations that just put out a log record -- this
  309.  *    would mean that undo operations would only reset marks, and not
  310.  *    cause any other change.
  311.  *
  312.  * PUBLIC: int log_mark __P((SCR *, LMARK *));
  313.  */
  314. int
  315. log_mark(sp, lmp)
  316.     SCR *sp;
  317.     LMARK *lmp;
  318. {
  319.     DBT data, key;
  320.     EXF *ep;
  321.  
  322.     ep = sp->ep;
  323.     if (F_ISSET(ep, F_NOLOG))
  324.         return (0);
  325.  
  326.     /* Put out one initial cursor record per set of changes. */
  327.     if (ep->l_cursor.lno != OOBLNO) {
  328.         if (log_cursor1(sp, LOG_CURSOR_INIT))
  329.             return (1);
  330.         ep->l_cursor.lno = OOBLNO;
  331.     }
  332.  
  333.     BINC_RET(sp, ep->l_lp,
  334.         ep->l_len, sizeof(u_char) + sizeof(LMARK));
  335.     ep->l_lp[0] = LOG_MARK;
  336.     memmove(ep->l_lp + sizeof(u_char), lmp, sizeof(LMARK));
  337.  
  338.     key.data = &ep->l_cur;
  339.     key.size = sizeof(recno_t);
  340.     data.data = ep->l_lp;
  341.     data.size = sizeof(u_char) + sizeof(LMARK);
  342.     if (ep->log->put(ep->log, &key, &data, 0) == -1)
  343.         LOG_ERR;
  344.  
  345. #if defined(DEBUG) && 0
  346.     TRACE(sp, "%lu: mark %c: %lu/%u\n",
  347.         ep->l_cur, lmp->name, lmp->lno, lmp->cno);
  348. #endif
  349.     /* Reset high water mark. */
  350.     ep->l_high = ++ep->l_cur;
  351.     return (0);
  352. }
  353.  
  354. /*
  355.  * Log_backward --
  356.  *    Roll the log backward one operation.
  357.  *
  358.  * PUBLIC: int log_backward __P((SCR *, MARK *));
  359.  */
  360. int
  361. log_backward(sp, rp)
  362.     SCR *sp;
  363.     MARK *rp;
  364. {
  365.     DBT key, data;
  366.     EXF *ep;
  367.     LMARK lm;
  368.     MARK m;
  369.     recno_t lno;
  370.     int didop;
  371.     u_char *p;
  372.  
  373.     ep = sp->ep;
  374.     if (F_ISSET(ep, F_NOLOG)) {
  375.         msgq(sp, M_ERR,
  376.             "010|Logging not being performed, undo not possible");
  377.         return (1);
  378.     }
  379.  
  380.     if (ep->l_cur == 1) {
  381.         msgq(sp, M_BERR, "011|No changes to undo");
  382.         return (1);
  383.     }
  384.  
  385.     F_SET(ep, F_NOLOG);        /* Turn off logging. */
  386.  
  387.     key.data = &ep->l_cur;        /* Initialize db request. */
  388.     key.size = sizeof(recno_t);
  389.     for (didop = 0;;) {
  390.         --ep->l_cur;
  391.         if (ep->log->get(ep->log, &key, &data, 0))
  392.             LOG_ERR;
  393. #if defined(DEBUG) && 0
  394.         log_trace(sp, "log_backward", ep->l_cur, data.data);
  395. #endif
  396.         switch (*(p = (u_char *)data.data)) {
  397.         case LOG_CURSOR_INIT:
  398.             if (didop) {
  399.                 memmove(rp, p + sizeof(u_char), sizeof(MARK));
  400.                 F_CLR(ep, F_NOLOG);
  401.                 return (0);
  402.             }
  403.             break;
  404.         case LOG_CURSOR_END:
  405.             break;
  406.         case LOG_LINE_APPEND:
  407.         case LOG_LINE_INSERT:
  408.             didop = 1;
  409.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  410.             if (db_delete(sp, lno))
  411.                 goto err;
  412.             ++sp->rptlines[L_DELETED];
  413.             break;
  414.         case LOG_LINE_DELETE:
  415.             didop = 1;
  416.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  417.             if (db_insert(sp, lno, p + sizeof(u_char) +
  418.                 sizeof(recno_t), data.size - sizeof(u_char) -
  419.                 sizeof(recno_t)))
  420.                 goto err;
  421.             ++sp->rptlines[L_ADDED];
  422.             break;
  423.         case LOG_LINE_RESET_F:
  424.             break;
  425.         case LOG_LINE_RESET_B:
  426.             didop = 1;
  427.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  428.             if (db_set(sp, lno, p + sizeof(u_char) +
  429.                 sizeof(recno_t), data.size - sizeof(u_char) -
  430.                 sizeof(recno_t)))
  431.                 goto err;
  432.             if (sp->rptlchange != lno) {
  433.                 sp->rptlchange = lno;
  434.                 ++sp->rptlines[L_CHANGED];
  435.             }
  436.             break;
  437.         case LOG_MARK:
  438.             didop = 1;
  439.             memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
  440.             m.lno = lm.lno;
  441.             m.cno = lm.cno;
  442.             if (mark_set(sp, lm.name, &m, 0))
  443.                 goto err;
  444.             break;
  445.         default:
  446.             abort();
  447.         }
  448.     }
  449.  
  450. err:    F_CLR(ep, F_NOLOG);
  451.     return (1);
  452. }
  453.  
  454. /*
  455.  * Log_setline --
  456.  *    Reset the line to its original appearance.
  457.  *
  458.  * XXX
  459.  * There's a bug in this code due to our not logging cursor movements
  460.  * unless a change was made.  If you do a change, move off the line,
  461.  * then move back on and do a 'U', the line will be restored to the way
  462.  * it was before the original change.
  463.  *
  464.  * PUBLIC: int log_setline __P((SCR *));
  465.  */
  466. int
  467. log_setline(sp)
  468.     SCR *sp;
  469. {
  470.     DBT key, data;
  471.     EXF *ep;
  472.     LMARK lm;
  473.     MARK m;
  474.     recno_t lno;
  475.     u_char *p;
  476.  
  477.     ep = sp->ep;
  478.     if (F_ISSET(ep, F_NOLOG)) {
  479.         msgq(sp, M_ERR,
  480.             "012|Logging not being performed, undo not possible");
  481.         return (1);
  482.     }
  483.  
  484.     if (ep->l_cur == 1)
  485.         return (1);
  486.  
  487.     F_SET(ep, F_NOLOG);        /* Turn off logging. */
  488.  
  489.     key.data = &ep->l_cur;        /* Initialize db request. */
  490.     key.size = sizeof(recno_t);
  491.  
  492.     for (;;) {
  493.         --ep->l_cur;
  494.         if (ep->log->get(ep->log, &key, &data, 0))
  495.             LOG_ERR;
  496. #if defined(DEBUG) && 0
  497.         log_trace(sp, "log_setline", ep->l_cur, data.data);
  498. #endif
  499.         switch (*(p = (u_char *)data.data)) {
  500.         case LOG_CURSOR_INIT:
  501.             memmove(&m, p + sizeof(u_char), sizeof(MARK));
  502.             if (m.lno != sp->lno || ep->l_cur == 1) {
  503.                 F_CLR(ep, F_NOLOG);
  504.                 return (0);
  505.             }
  506.             break;
  507.         case LOG_CURSOR_END:
  508.             memmove(&m, p + sizeof(u_char), sizeof(MARK));
  509.             if (m.lno != sp->lno) {
  510.                 ++ep->l_cur;
  511.                 F_CLR(ep, F_NOLOG);
  512.                 return (0);
  513.             }
  514.             break;
  515.         case LOG_LINE_APPEND:
  516.         case LOG_LINE_INSERT:
  517.         case LOG_LINE_DELETE:
  518.         case LOG_LINE_RESET_F:
  519.             break;
  520.         case LOG_LINE_RESET_B:
  521.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  522.             if (lno == sp->lno &&
  523.                 db_set(sp, lno, p + sizeof(u_char) +
  524.                 sizeof(recno_t), data.size - sizeof(u_char) -
  525.                 sizeof(recno_t)))
  526.                 goto err;
  527.             if (sp->rptlchange != lno) {
  528.                 sp->rptlchange = lno;
  529.                 ++sp->rptlines[L_CHANGED];
  530.             }
  531.         case LOG_MARK:
  532.             memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
  533.             m.lno = lm.lno;
  534.             m.cno = lm.cno;
  535.             if (mark_set(sp, lm.name, &m, 0))
  536.                 goto err;
  537.             break;
  538.         default:
  539.             abort();
  540.         }
  541.     }
  542.  
  543. err:    F_CLR(ep, F_NOLOG);
  544.     return (1);
  545. }
  546.  
  547. /*
  548.  * Log_forward --
  549.  *    Roll the log forward one operation.
  550.  *
  551.  * PUBLIC: int log_forward __P((SCR *, MARK *));
  552.  */
  553. int
  554. log_forward(sp, rp)
  555.     SCR *sp;
  556.     MARK *rp;
  557. {
  558.     DBT key, data;
  559.     EXF *ep;
  560.     LMARK lm;
  561.     MARK m;
  562.     recno_t lno;
  563.     int didop;
  564.     u_char *p;
  565.  
  566.     ep = sp->ep;
  567.     if (F_ISSET(ep, F_NOLOG)) {
  568.         msgq(sp, M_ERR,
  569.         "013|Logging not being performed, roll-forward not possible");
  570.         return (1);
  571.     }
  572.  
  573.     if (ep->l_cur == ep->l_high) {
  574.         msgq(sp, M_BERR, "014|No changes to re-do");
  575.         return (1);
  576.     }
  577.  
  578.     F_SET(ep, F_NOLOG);        /* Turn off logging. */
  579.  
  580.     key.data = &ep->l_cur;        /* Initialize db request. */
  581.     key.size = sizeof(recno_t);
  582.     for (didop = 0;;) {
  583.         ++ep->l_cur;
  584.         if (ep->log->get(ep->log, &key, &data, 0))
  585.             LOG_ERR;
  586. #if defined(DEBUG) && 0
  587.         log_trace(sp, "log_forward", ep->l_cur, data.data);
  588. #endif
  589.         switch (*(p = (u_char *)data.data)) {
  590.         case LOG_CURSOR_END:
  591.             if (didop) {
  592.                 ++ep->l_cur;
  593.                 memmove(rp, p + sizeof(u_char), sizeof(MARK));
  594.                 F_CLR(ep, F_NOLOG);
  595.                 return (0);
  596.             }
  597.             break;
  598.         case LOG_CURSOR_INIT:
  599.             break;
  600.         case LOG_LINE_APPEND:
  601.         case LOG_LINE_INSERT:
  602.             didop = 1;
  603.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  604.             if (db_insert(sp, lno, p + sizeof(u_char) +
  605.                 sizeof(recno_t), data.size - sizeof(u_char) -
  606.                 sizeof(recno_t)))
  607.                 goto err;
  608.             ++sp->rptlines[L_ADDED];
  609.             break;
  610.         case LOG_LINE_DELETE:
  611.             didop = 1;
  612.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  613.             if (db_delete(sp, lno))
  614.                 goto err;
  615.             ++sp->rptlines[L_DELETED];
  616.             break;
  617.         case LOG_LINE_RESET_B:
  618.             break;
  619.         case LOG_LINE_RESET_F:
  620.             didop = 1;
  621.             memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  622.             if (db_set(sp, lno, p + sizeof(u_char) +
  623.                 sizeof(recno_t), data.size - sizeof(u_char) -
  624.                 sizeof(recno_t)))
  625.                 goto err;
  626.             if (sp->rptlchange != lno) {
  627.                 sp->rptlchange = lno;
  628.                 ++sp->rptlines[L_CHANGED];
  629.             }
  630.             break;
  631.         case LOG_MARK:
  632.             didop = 1;
  633.             memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
  634.             m.lno = lm.lno;
  635.             m.cno = lm.cno;
  636.             if (mark_set(sp, lm.name, &m, 0))
  637.                 goto err;
  638.             break;
  639.         default:
  640.             abort();
  641.         }
  642.     }
  643.  
  644. err:    F_CLR(ep, F_NOLOG);
  645.     return (1);
  646. }
  647.  
  648. /*
  649.  * log_err --
  650.  *    Try and restart the log on failure, i.e. if we run out of memory.
  651.  */
  652. static void
  653. log_err(sp, file, line)
  654.     SCR *sp;
  655.     char *file;
  656.     int line;
  657. {
  658.     EXF *ep;
  659.  
  660.     msgq(sp, M_SYSERR, "015|%s/%d: log put error", tail(file), line);
  661.     ep = sp->ep;
  662.     (void)ep->log->close(ep->log);
  663.     if (!log_init(sp, ep))
  664.         msgq(sp, M_ERR, "267|Log restarted");
  665. }
  666.  
  667. #if defined(DEBUG) && 0
  668. static void
  669. log_trace(sp, msg, rno, p)
  670.     SCR *sp;
  671.     char *msg;
  672.     recno_t rno;
  673.     u_char *p;
  674. {
  675.     LMARK lm;
  676.     MARK m;
  677.     recno_t lno;
  678.  
  679.     switch (*p) {
  680.     case LOG_CURSOR_INIT:
  681.         memmove(&m, p + sizeof(u_char), sizeof(MARK));
  682.         TRACE(sp, "%lu: %s:  C_INIT: %u/%u\n", rno, msg, m.lno, m.cno);
  683.         break;
  684.     case LOG_CURSOR_END:
  685.         memmove(&m, p + sizeof(u_char), sizeof(MARK));
  686.         TRACE(sp, "%lu: %s:   C_END: %u/%u\n", rno, msg, m.lno, m.cno);
  687.         break;
  688.     case LOG_LINE_APPEND:
  689.         memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  690.         TRACE(sp, "%lu: %s:  APPEND: %lu\n", rno, msg, lno);
  691.         break;
  692.     case LOG_LINE_INSERT:
  693.         memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  694.         TRACE(sp, "%lu: %s:  INSERT: %lu\n", rno, msg, lno);
  695.         break;
  696.     case LOG_LINE_DELETE:
  697.         memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  698.         TRACE(sp, "%lu: %s:  DELETE: %lu\n", rno, msg, lno);
  699.         break;
  700.     case LOG_LINE_RESET_F:
  701.         memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  702.         TRACE(sp, "%lu: %s: RESET_F: %lu\n", rno, msg, lno);
  703.         break;
  704.     case LOG_LINE_RESET_B:
  705.         memmove(&lno, p + sizeof(u_char), sizeof(recno_t));
  706.         TRACE(sp, "%lu: %s: RESET_B: %lu\n", rno, msg, lno);
  707.         break;
  708.     case LOG_MARK:
  709.         memmove(&lm, p + sizeof(u_char), sizeof(LMARK));
  710.         TRACE(sp,
  711.             "%lu: %s:    MARK: %u/%u\n", rno, msg, lm.lno, lm.cno);
  712.         break;
  713.     default:
  714.         abort();
  715.     }
  716. }
  717. #endif
  718.