(linenum→info "unix/slp.c:2238")

emacs/22.1/src/abbrev.c

    1: /* Primitives for word-abbrev mode.
    2:    Copyright (C) 1985, 1986, 1993, 1996, 1998, 2001, 2002, 2003, 2004,
    3:                  2005, 2006, 2007 Free Software Foundation, Inc.
    4: 
    5: This file is part of GNU Emacs.
    6: 
    7: GNU Emacs is free software; you can redistribute it and/or modify
    8: it under the terms of the GNU General Public License as published by
    9: the Free Software Foundation; either version 2, or (at your option)
   10: any later version.
   11: 
   12: GNU Emacs is distributed in the hope that it will be useful,
   13: but WITHOUT ANY WARRANTY; without even the implied warranty of
   14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15: GNU General Public License for more details.
   16: 
   17: You should have received a copy of the GNU General Public License
   18: along with GNU Emacs; see the file COPYING.  If not, write to
   19: the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   20: Boston, MA 02110-1301, USA.  */
   21: 
   22: 
   23: #include <config.h>
   24: #include <stdio.h>
   25: 
   26: #include "lisp.h"
   27: #include "commands.h"
   28: #include "buffer.h"
   29: #include "window.h"
   30: #include "charset.h"
   31: #include "syntax.h"
   32: 
   33: /* An abbrev table is an obarray.
   34:  Each defined abbrev is represented by a symbol in that obarray
   35:  whose print name is the abbreviation.
   36:  The symbol's value is a string which is the expansion.
   37:  If its function definition is non-nil, it is called
   38:   after the expansion is done.
   39:  The plist slot of the abbrev symbol is its usage count. */
   40: 
   41: /* List of all abbrev-table name symbols:
   42:  symbols whose values are abbrev tables.  */
   43: 
   44: Lisp_Object Vabbrev_table_name_list;
   45: 
   46: /* The table of global abbrevs.  These are in effect
   47:  in any buffer in which abbrev mode is turned on. */
   48: 
   49: Lisp_Object Vglobal_abbrev_table;
   50: 
   51: /* The local abbrev table used by default (in Fundamental Mode buffers) */
   52: 
   53: Lisp_Object Vfundamental_mode_abbrev_table;
   54: 
   55: /* Set nonzero when an abbrev definition is changed */
   56: 
   57: int abbrevs_changed;
   58: 
   59: int abbrev_all_caps;
   60: 
   61: /* Non-nil => use this location as the start of abbrev to expand
   62:  (rather than taking the word before point as the abbrev) */
   63: 
   64: Lisp_Object Vabbrev_start_location;
   65: 
   66: /* Buffer that Vabbrev_start_location applies to */
   67: Lisp_Object Vabbrev_start_location_buffer;
   68: 
   69: /* The symbol representing the abbrev most recently expanded */
   70: 
   71: Lisp_Object Vlast_abbrev;
   72: 
   73: /* A string for the actual text of the abbrev most recently expanded.
   74:    This has more info than Vlast_abbrev since case is significant.  */
   75: 
   76: Lisp_Object Vlast_abbrev_text;
   77: 
   78: /* Character address of start of last abbrev expanded */
   79: 
   80: EMACS_INT last_abbrev_point;
   81: 
   82: /* Hook to run before expanding any abbrev.  */
   83: 
   84: Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook;
   85: 
   86: Lisp_Object Qsystem_type, Qcount, Qforce;
   87: ^L
   88: DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
   89:        doc: /* Create a new, empty abbrev table object.  */)
   90:      ()
   91: {
   92:   /* The value 59 is arbitrary chosen prime number.  */
   93:   return Fmake_vector (make_number (59), make_number (0));
   94: }
   95: 
   96: DEFUN ("clear-abbrev-table", Fclear_abbrev_table, Sclear_abbrev_table, 1, 1, 0,
   97:        doc: /* Undefine all abbrevs in abbrev table TABLE, leaving it empty.  */)
   98:      (table)
   99:      Lisp_Object table;
  100: {
  101:   int i, size;
  102: 
  103:   CHECK_VECTOR (table);
  104:   size = XVECTOR (table)->size;
  105:   abbrevs_changed = 1;
  106:   for (i = 0; i < size; i++)
  107:     XVECTOR (table)->contents[i] = make_number (0);
  108:   return Qnil;
  109: }
  110: 
  111: DEFUN ("define-abbrev", Fdefine_abbrev, Sdefine_abbrev, 3, 6, 0,
  112:        doc: /* Define an abbrev in TABLE named NAME, to expand to EXPANSION and call HOOK.
  113: NAME must be a string, and should be lower-case.
  114: EXPANSION should usually be a string.
  115: To undefine an abbrev, define it with EXPANSION = nil.
  116: If HOOK is non-nil, it should be a function of no arguments;
  117: it is called after EXPANSION is inserted.
  118: If EXPANSION is not a string, the abbrev is a special one,
  119:  which does not expand in the usual way but only runs HOOK.
  120: 
  121: COUNT, if specified, gives the initial value for the abbrev's
  122: usage-count, which is incremented each time the abbrev is used.
  123: \(The default is zero.)
  124: 
  125: SYSTEM-FLAG, if non-nil, says that this is a "system" abbreviation
  126: which should not be saved in the user's abbreviation file.
  127: Unless SYSTEM-FLAG is `force', a system abbreviation will not
  128: overwrite a non-system abbreviation of the same name.  */)
  129:      (table, name, expansion, hook, count, system_flag)
  130:      Lisp_Object table, name, expansion, hook, count, system_flag;
  131: {
  132:   Lisp_Object sym, oexp, ohook, tem;
  133:   CHECK_VECTOR (table);
  134:   CHECK_STRING (name);
  135: 
  136:   /* If defining a system abbrev, do not overwrite a non-system abbrev
  137:      of the same name, unless 'force is used. */
  138:   if (!NILP (system_flag) && !EQ (system_flag, Qforce))
  139:     {
  140:       sym = Fintern_soft (name, table);
  141: 
  142:       if (!NILP (SYMBOL_VALUE (sym)) &&
  143:           NILP (Fplist_get (XSYMBOL (sym)->plist, Qsystem_type))) return Qnil;
  144:     }
  145: 
  146:   if (NILP (count))
  147:     count = make_number (0);
  148:   else
  149:     CHECK_NUMBER (count);
  150: 
  151:   sym = Fintern (name, table);
  152: 
  153:   oexp = SYMBOL_VALUE (sym);
  154:   ohook = XSYMBOL (sym)->function;
  155:   if (!((EQ (oexp, expansion)
  156:          || (STRINGP (oexp) && STRINGP (expansion)
  157:              && (tem = Fstring_equal (oexp, expansion), !NILP (tem))))
  158:         &&
  159:         (EQ (ohook, hook)
  160:          || (tem = Fequal (ohook, hook), !NILP (tem))))
  161:       && NILP (system_flag))
  162:     abbrevs_changed = 1;
  163: 
  164:   Fset (sym, expansion);
  165:   Ffset (sym, hook);
  166: 
  167:   if (! NILP (system_flag))
  168:     Fsetplist (sym, list4 (Qcount, count, Qsystem_type, system_flag));
  169:   else
  170:     Fsetplist (sym, count);
  171: 
  172:   return name;
  173: }
  174: 
  175: DEFUN ("define-global-abbrev", Fdefine_global_abbrev, Sdefine_global_abbrev, 2, 2,
  176:        "sDefine global abbrev: \nsExpansion for %s: ",
  177:        doc: /* Define ABBREV as a global abbreviation for EXPANSION.  */)
  178:      (abbrev, expansion)
  179:      Lisp_Object abbrev, expansion;
  180: {
  181:   Fdefine_abbrev (Vglobal_abbrev_table, Fdowncase (abbrev),
  182:                   expansion, Qnil, make_number (0), Qnil);
  183:   return abbrev;
  184: }
  185: 
  186: DEFUN ("define-mode-abbrev", Fdefine_mode_abbrev, Sdefine_mode_abbrev, 2, 2,
  187:        "sDefine mode abbrev: \nsExpansion for %s: ",
  188:        doc: /* Define ABBREV as a mode-specific abbreviation for EXPANSION.  */)
  189:      (abbrev, expansion)
  190:      Lisp_Object abbrev, expansion;
  191: {
  192:   if (NILP (current_buffer->abbrev_table))
  193:     error ("Major mode has no abbrev table");
  194: 
  195:   Fdefine_abbrev (current_buffer->abbrev_table, Fdowncase (abbrev),
  196:                   expansion, Qnil, make_number (0), Qnil);
  197:   return abbrev;
  198: }
  199: 
  200: DEFUN ("abbrev-symbol", Fabbrev_symbol, Sabbrev_symbol, 1, 2, 0,
  201:        doc: /* Return the symbol representing abbrev named ABBREV.
  202: This symbol's name is ABBREV, but it is not the canonical symbol of that name;
  203: it is interned in an abbrev-table rather than the normal obarray.
  204: The value is nil if that abbrev is not defined.
  205: Optional second arg TABLE is abbrev table to look it up in.
  206: The default is to try buffer's mode-specific abbrev table, then global table.  */)
  207:      (abbrev, table)
  208:      Lisp_Object abbrev, table;
  209: {
  210:   Lisp_Object sym;
  211:   CHECK_STRING (abbrev);
  212:   if (!NILP (table))
  213:     sym = Fintern_soft (abbrev, table);
  214:   else
  215:     {
  216:       sym = Qnil;
  217:       if (!NILP (current_buffer->abbrev_table))
  218:         sym = Fintern_soft (abbrev, current_buffer->abbrev_table);
  219:       if (NILP (SYMBOL_VALUE (sym)))
  220:         sym = Qnil;
  221:       if (NILP (sym))
  222:         sym = Fintern_soft (abbrev, Vglobal_abbrev_table);
  223:     }
  224:   if (NILP (SYMBOL_VALUE (sym)))
  225:     return Qnil;
  226:   return sym;
  227: }
  228: 
  229: DEFUN ("abbrev-expansion", Fabbrev_expansion, Sabbrev_expansion, 1, 2, 0,
  230:        doc: /* Return the string that ABBREV expands into in the current buffer.
  231: Optionally specify an abbrev table as second arg;
  232: then ABBREV is looked up in that table only.  */)
  233:      (abbrev, table)
  234:      Lisp_Object abbrev, table;
  235: {
  236:   Lisp_Object sym;
  237:   sym = Fabbrev_symbol (abbrev, table);
  238:   if (NILP (sym)) return sym;
  239:   return Fsymbol_value (sym);
  240: }
  241: ^L
  242: /* Expand the word before point, if it is an abbrev.
  243:   Returns 1 if an expansion is done. */
  244: 
  245: DEFUN ("expand-abbrev", Fexpand_abbrev, Sexpand_abbrev, 0, 0, "",
  246:        doc: /* Expand the abbrev before point, if there is an abbrev there.
  247: Effective when explicitly called even when `abbrev-mode' is nil.
  248: Returns the abbrev symbol, if expansion took place.  */)
  249:      ()
  250: {
  251:   register char *buffer, *p;
  252:   int wordstart, wordend;
  253:   register int wordstart_byte, wordend_byte, idx, idx_byte;
  254:   int whitecnt;
  255:   int uccount = 0, lccount = 0;
  256:   register Lisp_Object sym;
  257:   Lisp_Object expansion, hook, tem;
  258:   Lisp_Object value;
  259:   int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
  260: 
  261:   value = Qnil;
  262: 
  263:   Frun_hooks (1, &Qpre_abbrev_expand_hook);
  264: 
  265:   wordstart = 0;
  266:   if (!(BUFFERP (Vabbrev_start_location_buffer)
  267:         && XBUFFER (Vabbrev_start_location_buffer) == current_buffer))
  268:     Vabbrev_start_location = Qnil;
  269:   if (!NILP (Vabbrev_start_location))
  270:     {
  271:       tem = Vabbrev_start_location;
  272:       CHECK_NUMBER_COERCE_MARKER (tem);
  273:       wordstart = XINT (tem);
  274:       Vabbrev_start_location = Qnil;
  275:       if (wordstart < BEGV || wordstart > ZV)
  276:         wordstart = 0;
  277:       if (wordstart && wordstart != ZV)
  278:         {
  279:           wordstart_byte = CHAR_TO_BYTE (wordstart);
  280:           if (FETCH_BYTE (wordstart_byte) == '-')
  281:             del_range (wordstart, wordstart + 1);
  282:         }
  283:     }
  284:   if (!wordstart)
  285:     wordstart = scan_words (PT, -1);
  286: 
  287:   if (!wordstart)
  288:     return value;
  289: 
  290:   wordstart_byte = CHAR_TO_BYTE (wordstart);
  291:   wordend = scan_words (wordstart, 1);
  292:   if (!wordend)
  293:     return value;
  294: 
  295:   if (wordend > PT)
  296:     wordend = PT;
  297: 
  298:   wordend_byte = CHAR_TO_BYTE (wordend);
  299:   whitecnt = PT - wordend;
  300:   if (wordend <= wordstart)
  301:     return value;
  302: 
  303:   p = buffer = (char *) alloca (wordend_byte - wordstart_byte);
  304: 
  305:   for (idx = wordstart, idx_byte = wordstart_byte; idx < wordend; )
  306:     {
  307:       register int c;
  308: 
  309:       if (multibyte)
  310:         {
  311:           FETCH_CHAR_ADVANCE (c, idx, idx_byte);
  312:         }
  313:       else
  314:         {
  315:           c = FETCH_BYTE (idx_byte);
  316:           idx++, idx_byte++;
  317:         }
  318: 
  319:       if (UPPERCASEP (c))
  320:         c = DOWNCASE (c), uccount++;
  321:       else if (! NOCASEP (c))
  322:         lccount++;
  323:       if (multibyte)
  324:         p += CHAR_STRING (c, p);
  325:       else
  326:         *p++ = c;
  327:     }
  328: 
  329:   if (VECTORP (current_buffer->abbrev_table))
  330:     sym = oblookup (current_buffer->abbrev_table, buffer,
  331:                     wordend - wordstart, p - buffer);
  332:   else
  333:     XSETFASTINT (sym, 0);
  334: 
  335:   if (INTEGERP (sym) || NILP (SYMBOL_VALUE (sym)))
  336:     sym = oblookup (Vglobal_abbrev_table, buffer,
  337:                     wordend - wordstart, p - buffer);
  338:   if (INTEGERP (sym) || NILP (SYMBOL_VALUE (sym)))
  339:     return value;
  340: 
  341:   if (INTERACTIVE && !EQ (minibuf_window, selected_window))
  342:     {
  343:       /* Add an undo boundary, in case we are doing this for
  344:          a self-inserting command which has avoided making one so far.  */
  345:       SET_PT (wordend);
  346:       Fundo_boundary ();
  347:     }
  348: 
  349:   Vlast_abbrev_text
  350:     = Fbuffer_substring (make_number (wordstart), make_number (wordend));
  351: 
  352:   /* Now sym is the abbrev symbol.  */
  353:   Vlast_abbrev = sym;
  354:   value = sym;
  355:   last_abbrev_point = wordstart;
  356: 
  357:   /* Increment use count.  */
  358:   if (INTEGERP (XSYMBOL (sym)->plist))
  359:     XSETINT (XSYMBOL (sym)->plist,
  360:              XINT (XSYMBOL (sym)->plist) + 1);
  361:   else if (INTEGERP (tem = Fget (sym, Qcount)))
  362:     Fput (sym, Qcount, make_number (XINT (tem) + 1));
  363: 
  364:   /* If this abbrev has an expansion, delete the abbrev
  365:      and insert the expansion.  */
  366:   expansion = SYMBOL_VALUE (sym);
  367:   if (STRINGP (expansion))
  368:     {
  369:       SET_PT (wordstart);
  370: 
  371:       insert_from_string (expansion, 0, 0, SCHARS (expansion),
  372:                           SBYTES (expansion), 1);
  373:       del_range_both (PT, PT_BYTE,
  374:                       wordend + (PT - wordstart),
  375:                       wordend_byte + (PT_BYTE - wordstart_byte),
  376:                       1);
  377: 
  378:       SET_PT (PT + whitecnt);
  379: 
  380:       if (uccount && !lccount)
  381:         {
  382:           /* Abbrev was all caps */
  383:           /* If expansion is multiple words, normally capitalize each word */
  384:           /* This used to be if (!... && ... >= ...) Fcapitalize; else Fupcase
  385:              but Megatest 68000 compiler can't handle that */
  386:           if (!abbrev_all_caps)
  387:             if (scan_words (PT, -1) > scan_words (wordstart, 1))
  388:               {
  389:                 Fupcase_initials_region (make_number (wordstart),
  390:                                          make_number (PT));
  391:                 goto caped;
  392:               }
  393:           /* If expansion is one word, or if user says so, upcase it all. */
  394:           Fupcase_region (make_number (wordstart), make_number (PT));
  395:         caped: ;
  396:         }
  397:       else if (uccount)
  398:         {
  399:           /* Abbrev included some caps.  Cap first initial of expansion */
  400:           int pos = wordstart_byte;
  401: 
  402:           /* Find the initial.  */
  403:           while (pos < PT_BYTE
  404:                  && SYNTAX (*BUF_BYTE_ADDRESS (current_buffer, pos)) != Sword)
  405:             pos++;
  406: 
  407:           /* Change just that.  */
  408:           pos = BYTE_TO_CHAR (pos);
  409:           Fupcase_initials_region (make_number (pos), make_number (pos + 1));
  410:         }
  411:     }
  412: 
  413:   hook = XSYMBOL (sym)->function;
  414:   if (!NILP (hook))
  415:     {
  416:       Lisp_Object expanded, prop;
  417: 
  418:       /* If the abbrev has a hook function, run it.  */
  419:       expanded = call0 (hook);
  420: 
  421:       /* In addition, if the hook function is a symbol with
  422:          a non-nil `no-self-insert' property, let the value it returned
  423:          specify whether we consider that an expansion took place.  If
  424:          it returns nil, no expansion has been done.  */
  425: 
  426:       if (SYMBOLP (hook)
  427:           && NILP (expanded)
  428:           && (prop = Fget (hook, intern ("no-self-insert")),
  429:               !NILP (prop)))
  430:         value = Qnil;
  431:     }
  432: 
  433:   return value;
  434: }
  435: 
  436: DEFUN ("unexpand-abbrev", Funexpand_abbrev, Sunexpand_abbrev, 0, 0, "",
  437:        doc: /* Undo the expansion of the last abbrev that expanded.
  438: This differs from ordinary undo in that other editing done since then
  439: is not undone.  */)
  440:      ()
  441: {
  442:   int opoint = PT;
  443:   int adjust = 0;
  444:   if (last_abbrev_point < BEGV
  445:       || last_abbrev_point > ZV)
  446:     return Qnil;
  447:   SET_PT (last_abbrev_point);
  448:   if (STRINGP (Vlast_abbrev_text))
  449:     {
  450:       /* This isn't correct if Vlast_abbrev->function was used
  451:          to do the expansion */
  452:       Lisp_Object val;
  453:       int zv_before;
  454: 
  455:       val = SYMBOL_VALUE (Vlast_abbrev);
  456:       if (!STRINGP (val))
  457:         error ("Value of `abbrev-symbol' must be a string");
  458:       zv_before = ZV;
  459:       del_range_byte (PT_BYTE, PT_BYTE + SBYTES (val), 1);
  460:       /* Don't inherit properties here; just copy from old contents.  */
  461:       insert_from_string (Vlast_abbrev_text, 0, 0,
  462:                           SCHARS (Vlast_abbrev_text),
  463:                           SBYTES (Vlast_abbrev_text), 0);
  464:       Vlast_abbrev_text = Qnil;
  465:       /* Total number of characters deleted.  */
  466:       adjust = ZV - zv_before;
  467:     }
  468:   SET_PT (last_abbrev_point < opoint ? opoint + adjust : opoint);
  469:   return Qnil;
  470: }
  471: ^L
  472: static void
  473: write_abbrev (sym, stream)
  474:      Lisp_Object sym, stream;
  475: {
  476:   Lisp_Object name, count, system_flag;
  477: 
  478:   if (INTEGERP (XSYMBOL (sym)->plist))
  479:     {
  480:       count = XSYMBOL (sym)->plist;
  481:       system_flag = Qnil;
  482:     }
  483:   else
  484:     {
  485:       count = Fget (sym, Qcount);
  486:       system_flag = Fget (sym, Qsystem_type);
  487:     }
  488: 
  489:   if (NILP (SYMBOL_VALUE (sym)) || ! NILP (system_flag))
  490:     return;
  491: 
  492:   insert ("    (", 5);
  493:   name = SYMBOL_NAME (sym);
  494:   Fprin1 (name, stream);
  495:   insert (" ", 1);
  496:   Fprin1 (SYMBOL_VALUE (sym), stream);
  497:   insert (" ", 1);
  498:   Fprin1 (XSYMBOL (sym)->function, stream);
  499:   insert (" ", 1);
  500:   Fprin1 (count, stream);
  501:   insert (")\n", 2);
  502: }
  503: 
  504: static void
  505: describe_abbrev (sym, stream)
  506:      Lisp_Object sym, stream;
  507: {
  508:   Lisp_Object one, count, system_flag;
  509: 
  510:   if (INTEGERP (XSYMBOL (sym)->plist))
  511:     {
  512:       count = XSYMBOL (sym)->plist;
  513:       system_flag = Qnil;
  514:     }
  515:   else
  516:     {
  517:       count = Fget (sym, Qcount);
  518:       system_flag = Fget (sym, Qsystem_type);
  519:     }
  520: 
  521:   if (NILP (SYMBOL_VALUE (sym)))
  522:     return;
  523: 
  524:   one = make_number (1);
  525:   Fprin1 (Fsymbol_name (sym), stream);
  526: 
  527:   if (!NILP (system_flag))
  528:     {
  529:       insert_string (" (sys)");
  530:       Findent_to (make_number (20), one);
  531:     }
  532:   else
  533:     Findent_to (make_number (15), one);
  534: 
  535:   Fprin1 (count, stream);
  536:   Findent_to (make_number (20), one);
  537:   Fprin1 (SYMBOL_VALUE (sym), stream);
  538:   if (!NILP (XSYMBOL (sym)->function))
  539:     {
  540:       Findent_to (make_number (45), one);
  541:       Fprin1 (XSYMBOL (sym)->function, stream);
  542:     }
  543:   Fterpri (stream);
  544: }
  545: 
  546: static void
  547: record_symbol (sym, list)
  548:      Lisp_Object sym, list;
  549: {
  550:   XSETCDR (list, Fcons (sym, XCDR (list)));
  551: }
  552: 
  553: DEFUN ("insert-abbrev-table-description", Finsert_abbrev_table_description,
  554:        Sinsert_abbrev_table_description, 1, 2, 0,
  555:        doc: /* Insert before point a full description of abbrev table named NAME.
  556: NAME is a symbol whose value is an abbrev table.
  557: If optional 2nd arg READABLE is non-nil, a human-readable description
  558: is inserted.  Otherwise the description is an expression,
  559: a call to `define-abbrev-table', which would
  560: define the abbrev table NAME exactly as it is currently defined.
  561: 
  562: Abbrevs marked as "system abbrevs" are normally omitted.  However, if
  563: READABLE is non-nil, they are listed.  */)
  564:      (name, readable)
  565:      Lisp_Object name, readable;
  566: {
  567:   Lisp_Object table;
  568:   Lisp_Object symbols;
  569:   Lisp_Object stream;
  570: 
  571:   CHECK_SYMBOL (name);
  572:   table = Fsymbol_value (name);
  573:   CHECK_VECTOR (table);
  574: 
  575:   XSETBUFFER (stream, current_buffer);
  576: 
  577:   symbols = Fcons (Qnil, Qnil);
  578:   map_obarray (table, record_symbol, symbols);
  579:   symbols = XCDR (symbols);
  580:   symbols = Fsort (symbols, Qstring_lessp);
  581: 
  582:   if (!NILP (readable))
  583:     {
  584:       insert_string ("(");
  585:       Fprin1 (name, stream);
  586:       insert_string (")\n\n");
  587:       while (! NILP (symbols))
  588:         {
  589:           describe_abbrev (XCAR (symbols), stream);
  590:           symbols = XCDR (symbols);
  591:         }
  592: 
  593:       insert_string ("\n\n");
  594:     }
  595:   else
  596:     {
  597:       insert_string ("(define-abbrev-table '");
  598:       Fprin1 (name, stream);
  599:       insert_string (" '(\n");
  600:       while (! NILP (symbols))
  601:         {
  602:           write_abbrev (XCAR (symbols), stream);
  603:           symbols = XCDR (symbols);
  604:         }
  605:       insert_string ("    ))\n\n");
  606:     }
  607: 
  608:   return Qnil;
  609: