+DEFUN ("last", Flast, 1, 2, 0, /*
+Return the tail of list LIST, of length N (default 1).
+LIST may be a dotted list, but not a circular list.
+Optional argument N must be a non-negative integer.
+If N is zero, then the atom that terminates the list is returned.
+If N is greater than the length of LIST, then LIST itself is returned.
+*/
+ (list, n))
+{
+ int int_n, count;
+ Lisp_Object retval, tortoise, hare;
+
+ CHECK_LIST (list);
+
+ if (NILP (n))
+ int_n = 1;
+ else
+ {
+ CHECK_NATNUM (n);
+ int_n = XINT (n);
+ }
+
+ for (retval = tortoise = hare = list, count = 0;
+ CONSP (hare);
+ hare = XCDR (hare),
+ (int_n-- <= 0 ? ((void) (retval = XCDR (retval))) : (void)0),
+ count++)
+ {
+ if (count < CIRCULAR_LIST_SUSPICION_LENGTH) continue;
+
+ if (count & 1)
+ tortoise = XCDR (tortoise);
+ if (EQ (hare, tortoise))
+ signal_circular_list_error (list);
+ }
+
+ return retval;
+}
+
+DEFUN ("nbutlast", Fnbutlast, 1, 2, 0, /*
+Modify LIST to remove the last N (default 1) elements.
+If LIST has N or fewer elements, nil is returned and LIST is unmodified.
+*/
+ (list, n))
+{
+ int int_n;
+
+ CHECK_LIST (list);
+
+ if (NILP (n))
+ int_n = 1;
+ else
+ {
+ CHECK_NATNUM (n);
+ int_n = XINT (n);
+ }
+
+ {
+ Lisp_Object last_cons = list;
+
+ EXTERNAL_LIST_LOOP_1 (list)
+ {
+ if (int_n-- < 0)
+ last_cons = XCDR (last_cons);
+ }
+
+ if (int_n >= 0)
+ return Qnil;
+
+ XCDR (last_cons) = Qnil;
+ return list;
+ }
+}
+
+DEFUN ("butlast", Fbutlast, 1, 2, 0, /*
+Return a copy of LIST with the last N (default 1) elements removed.
+If LIST has N or fewer elements, nil is returned.
+*/
+ (list, n))
+{
+ int int_n;
+
+ CHECK_LIST (list);
+
+ if (NILP (n))
+ int_n = 1;
+ else
+ {
+ CHECK_NATNUM (n);
+ int_n = XINT (n);
+ }
+
+ {
+ Lisp_Object retval = Qnil;
+ Lisp_Object tail = list;
+
+ EXTERNAL_LIST_LOOP_1 (list)
+ {
+ if (--int_n < 0)
+ {
+ retval = Fcons (XCAR (tail), retval);
+ tail = XCDR (tail);
+ }
+ }
+
+ return Fnreverse (retval);
+ }
+}
+