root/src/doc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_bytecode_char
  2. get_doc_string
  3. read_doc_string
  4. reread_doc_file
  5. store_function_docstring
  6. DEFUN
  7. default_to_grave_quoting_style
  8. DEFUN
  9. syms_of_doc

     1 /* Record indices of function doc strings stored in a file. -*- coding: utf-8 -*-
     2 
     3 Copyright (C) 1985-1986, 1993-1995, 1997-2023 Free Software Foundation,
     4 Inc.
     5 
     6 This file is part of GNU Emacs.
     7 
     8 GNU Emacs is free software: you can redistribute it and/or modify
     9 it under the terms of the GNU General Public License as published by
    10 the Free Software Foundation, either version 3 of the License, or (at
    11 your option) any later version.
    12 
    13 GNU Emacs is distributed in the hope that it will be useful,
    14 but WITHOUT ANY WARRANTY; without even the implied warranty of
    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16 GNU General Public License for more details.
    17 
    18 You should have received a copy of the GNU General Public License
    19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    20 
    21 
    22 #include <config.h>
    23 
    24 #include <errno.h>
    25 #include <sys/types.h>
    26 #include <sys/file.h>   /* Must be after sys/types.h for USG.  */
    27 #include <fcntl.h>
    28 #include <unistd.h>
    29 
    30 #include <c-ctype.h>
    31 
    32 #include "lisp.h"
    33 #include "character.h"
    34 #include "coding.h"
    35 #include "buffer.h"
    36 #include "disptab.h"
    37 #include "intervals.h"
    38 #include "keymap.h"
    39 
    40 /* Buffer used for reading from documentation file.  */
    41 static char *get_doc_string_buffer;
    42 static ptrdiff_t get_doc_string_buffer_size;
    43 
    44 static unsigned char *read_bytecode_pointer;
    45 
    46 static char const sibling_etc[] = "../etc/";
    47 
    48 /* `readchar' in lread.c calls back here to fetch the next byte.
    49    If UNREADFLAG is 1, we unread a byte.  */
    50 
    51 int
    52 read_bytecode_char (bool unreadflag)
    53 {
    54   if (unreadflag)
    55     {
    56       read_bytecode_pointer--;
    57       return 0;
    58     }
    59   return *read_bytecode_pointer++;
    60 }
    61 
    62 /* Extract a doc string from a file.  FILEPOS says where to get it.
    63    If it is an integer, use that position in the standard DOC file.
    64    If it is (FILE . INTEGER), use FILE as the file name
    65    and INTEGER as the position in that file.
    66    But if INTEGER is negative, make it positive.
    67    (A negative integer is used for user variables, so we can distinguish
    68    them without actually fetching the doc string.)
    69 
    70    If the location does not point to the beginning of a docstring
    71    (e.g. because the file has been modified and the location is stale),
    72    return nil.
    73 
    74    If UNIBYTE, always make a unibyte string.
    75 
    76    If DEFINITION, assume this is for reading
    77    a dynamic function definition; convert the bytestring
    78    and the constants vector with appropriate byte handling,
    79    and return a cons cell.  */
    80 
    81 Lisp_Object
    82 get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
    83 {
    84   char *from, *to, *name, *p, *p1;
    85   Lisp_Object file, pos;
    86   specpdl_ref count = SPECPDL_INDEX ();
    87   Lisp_Object dir;
    88   USE_SAFE_ALLOCA;
    89 
    90   if (FIXNUMP (filepos))
    91     {
    92       file = Vdoc_file_name;
    93       dir = Vdoc_directory;
    94       pos = filepos;
    95     }
    96   else if (CONSP (filepos))
    97     {
    98       file = XCAR (filepos);
    99       dir = Fsymbol_value (Qlisp_directory);
   100       pos = XCDR (filepos);
   101     }
   102   else
   103     return Qnil;
   104 
   105   EMACS_INT position = eabs (XFIXNUM (pos));
   106 
   107   if (!STRINGP (dir))
   108     return Qnil;
   109 
   110   if (!STRINGP (file))
   111     return Qnil;
   112 
   113   /* Put the file name in NAME as a C string.
   114      If it is relative, combine it with Vdoc_directory.  */
   115 
   116   Lisp_Object tem = Ffile_name_absolute_p (file);
   117   file = ENCODE_FILE (file);
   118   Lisp_Object docdir
   119     = NILP (tem) ? ENCODE_FILE (dir) : empty_unibyte_string;
   120   ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1;
   121   if (will_dump_p ())
   122     docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc);
   123   name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file));
   124   lispstpcpy (lispstpcpy (name, docdir), file);
   125 
   126   int fd = emacs_open (name, O_RDONLY, 0);
   127   if (fd < 0)
   128     {
   129       if (will_dump_p ())
   130         {
   131           /* Preparing to dump; DOC file is probably not installed.
   132              So check in ../etc.  */
   133           lispstpcpy (stpcpy (name, sibling_etc), file);
   134 
   135           fd = emacs_open (name, O_RDONLY, 0);
   136         }
   137       if (fd < 0)
   138         {
   139           if (errno != ENOENT && errno != ENOTDIR)
   140             report_file_error ("Read error on documentation file", file);
   141 
   142           SAFE_FREE ();
   143           AUTO_STRING (cannot_open, "Cannot open doc string file \"");
   144           AUTO_STRING (quote_nl, "\"\n");
   145           return concat3 (cannot_open, file, quote_nl);
   146         }
   147     }
   148   record_unwind_protect_int (close_file_unwind, fd);
   149 
   150   /* Seek only to beginning of disk block.  */
   151   /* Make sure we read at least 1024 bytes before `position'
   152      so we can check the leading text for consistency.  */
   153   int offset = min (position, max (1024, position % (8 * 1024)));
   154   if (TYPE_MAXIMUM (off_t) < position
   155       || lseek (fd, position - offset, 0) < 0)
   156     error ("Position %"pI"d out of range in doc string file \"%s\"",
   157            position, name);
   158 
   159   /* Read the doc string into get_doc_string_buffer.
   160      P points beyond the data just read.  */
   161 
   162   p = get_doc_string_buffer;
   163   while (1)
   164     {
   165       ptrdiff_t space_left = (get_doc_string_buffer_size - 1
   166                               - (p - get_doc_string_buffer));
   167 
   168       /* Allocate or grow the buffer if we need to.  */
   169       if (space_left <= 0)
   170         {
   171           ptrdiff_t in_buffer = p - get_doc_string_buffer;
   172           get_doc_string_buffer
   173             = xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
   174                        16 * 1024, -1, 1);
   175           p = get_doc_string_buffer + in_buffer;
   176           space_left = (get_doc_string_buffer_size - 1
   177                         - (p - get_doc_string_buffer));
   178         }
   179 
   180       /* Read a disk block at a time.
   181          If we read the same block last time, maybe skip this?  */
   182       if (space_left > 1024 * 8)
   183         space_left = 1024 * 8;
   184       int nread = emacs_read_quit (fd, p, space_left);
   185       if (nread < 0)
   186         report_file_error ("Read error on documentation file", file);
   187       p[nread] = 0;
   188       if (!nread)
   189         break;
   190       if (p == get_doc_string_buffer)
   191         p1 = strchr (p + offset, '\037');
   192       else
   193         p1 = strchr (p, '\037');
   194       if (p1)
   195         {
   196           *p1 = 0;
   197           p = p1;
   198           break;
   199         }
   200       p += nread;
   201     }
   202   SAFE_FREE_UNBIND_TO (count, Qnil);
   203 
   204   /* Sanity checking.  */
   205   if (CONSP (filepos))
   206     {
   207       int test = 1;
   208       /* A dynamic docstring should be either at the very beginning of a "#@
   209          comment" or right after a dynamic docstring delimiter (in case we
   210          pack several such docstrings within the same comment).  */
   211       if (get_doc_string_buffer[offset - test] != '\037')
   212         {
   213           if (get_doc_string_buffer[offset - test++] != ' ')
   214             return Qnil;
   215           while (get_doc_string_buffer[offset - test] >= '0'
   216                  && get_doc_string_buffer[offset - test] <= '9')
   217             test++;
   218           if (get_doc_string_buffer[offset - test++] != '@'
   219               || get_doc_string_buffer[offset - test] != '#')
   220             return Qnil;
   221         }
   222     }
   223   else
   224     {
   225       int test = 1;
   226       if (get_doc_string_buffer[offset - test++] != '\n')
   227         return Qnil;
   228       while (get_doc_string_buffer[offset - test] > ' ')
   229         test++;
   230       if (get_doc_string_buffer[offset - test] != '\037')
   231         return Qnil;
   232     }
   233 
   234   /* Scan the text and perform quoting with ^A (char code 1).
   235      ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_.  */
   236   from = get_doc_string_buffer + offset;
   237   to = get_doc_string_buffer + offset;
   238   while (from != p)
   239     {
   240       if (*from == 1)
   241         {
   242           from++;
   243           int c = *from++;
   244           if (c == 1)
   245             *to++ = c;
   246           else if (c == '0')
   247             *to++ = 0;
   248           else if (c == '_')
   249             *to++ = 037;
   250           else
   251             {
   252               unsigned char uc = c;
   253               error ("\
   254 Invalid data in documentation file -- %c followed by code %03o",
   255                      1, uc);
   256             }
   257         }
   258       else
   259         *to++ = *from++;
   260     }
   261 
   262   /* If DEFINITION, read from this buffer
   263      the same way we would read bytes from a file.  */
   264   if (definition)
   265     {
   266       read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
   267       return Fread (Qlambda);
   268     }
   269 
   270   if (unibyte)
   271     return make_unibyte_string (get_doc_string_buffer + offset,
   272                                 to - (get_doc_string_buffer + offset));
   273   else
   274     {
   275       /* The data determines whether the string is multibyte.  */
   276       ptrdiff_t nchars
   277         = multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
   278                                     + offset),
   279                                    to - (get_doc_string_buffer + offset));
   280       return make_string_from_bytes (get_doc_string_buffer + offset,
   281                                      nchars,
   282                                      to - (get_doc_string_buffer + offset));
   283     }
   284 }
   285 
   286 /* Get a string from position FILEPOS and pass it through the Lisp reader.
   287    We use this for fetching the bytecode string and constants vector
   288    of a compiled function from the .elc file.  */
   289 
   290 Lisp_Object
   291 read_doc_string (Lisp_Object filepos)
   292 {
   293   return get_doc_string (filepos, 0, 1);
   294 }
   295 
   296 static bool
   297 reread_doc_file (Lisp_Object file)
   298 {
   299   if (NILP (file))
   300     Fsnarf_documentation (Vdoc_file_name);
   301   else
   302     save_match_data_load (file, Qt, Qt, Qt, Qnil);
   303 
   304   return 1;
   305 }
   306 
   307 DEFUN ("documentation", Fdocumentation, Sdocumentation, 1, 2, 0,
   308        doc: /* Return the documentation string of FUNCTION.
   309 Unless a non-nil second argument RAW is given, the
   310 string is passed through `substitute-command-keys'.  */)
   311   (Lisp_Object function, Lisp_Object raw)
   312 {
   313   Lisp_Object doc;
   314   bool try_reload = true;
   315 
   316  documentation:
   317 
   318   doc = Qnil;
   319 
   320   if (SYMBOLP (function))
   321     {
   322       Lisp_Object tem = Fget (function, Qfunction_documentation);
   323       if (!NILP (tem))
   324         return Fdocumentation_property (function, Qfunction_documentation,
   325                                         raw);
   326     }
   327 
   328   Lisp_Object fun = Findirect_function (function, Qnil);
   329   if (NILP (fun))
   330     xsignal1 (Qvoid_function, function);
   331   if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
   332     fun = XCDR (fun);
   333 #ifdef HAVE_NATIVE_COMP
   334   if (!NILP (Fsubr_native_elisp_p (fun)))
   335     doc = native_function_doc (fun);
   336   else
   337 #endif
   338   if (SUBRP (fun))
   339     doc = make_fixnum (XSUBR (fun)->doc);
   340 #ifdef HAVE_MODULES
   341   else if (MODULE_FUNCTIONP (fun))
   342     doc = module_function_documentation (XMODULE_FUNCTION (fun));
   343 #endif
   344   else
   345     doc = call1 (Qfunction_documentation, fun);
   346 
   347   /* If DOC is 0, it's typically because of a dumped file missing
   348      from the DOC file (bug in src/Makefile.in).  */
   349   if (BASE_EQ (doc, make_fixnum (0)))
   350     doc = Qnil;
   351   if (FIXNUMP (doc) || CONSP (doc))
   352     {
   353       Lisp_Object tem;
   354       tem = get_doc_string (doc, 0, 0);
   355       if (NILP (tem) && try_reload)
   356         {
   357           /* The file is newer, we need to reset the pointers.  */
   358           try_reload = reread_doc_file (Fcar_safe (doc));
   359           if (try_reload)
   360             {
   361               try_reload = false;
   362               goto documentation;
   363             }
   364         }
   365       else
   366         doc = tem;
   367     }
   368 
   369   if (NILP (raw))
   370     doc = call1 (Qsubstitute_command_keys, doc);
   371   return doc;
   372 }
   373 
   374 DEFUN ("documentation-property", Fdocumentation_property,
   375        Sdocumentation_property, 2, 3, 0,
   376        doc: /* Return the documentation string that is SYMBOL's PROP property.
   377 Third argument RAW omitted or nil means pass the result through
   378 `substitute-command-keys' if it is a string.
   379 
   380 This differs from `get' in that it can refer to strings stored in the
   381 `etc/DOC' file; and that it evaluates documentation properties that
   382 aren't strings.  */)
   383   (Lisp_Object symbol, Lisp_Object prop, Lisp_Object raw)
   384 {
   385   bool try_reload = true;
   386   Lisp_Object tem;
   387 
   388  documentation_property:
   389 
   390   tem = Fget (symbol, prop);
   391 
   392   /* If we don't have any documentation for this symbol (and we're asking for
   393      the variable documentation), try to see whether it's an indirect variable
   394      and get the documentation from there instead. */
   395   if (EQ (prop, Qvariable_documentation)
   396       && NILP (tem))
   397     {
   398       Lisp_Object indirect = Findirect_variable (symbol);
   399       if (!NILP (indirect))
   400         tem = Fget (indirect, prop);
   401     }
   402 
   403   if (BASE_EQ (tem, make_fixnum (0)))
   404     tem = Qnil;
   405 
   406   /* See if we want to look for the string in the DOC file. */
   407   if (FIXNUMP (tem) || (CONSP (tem) && FIXNUMP (XCDR (tem))))
   408     {
   409       Lisp_Object doc = tem;
   410       tem = get_doc_string (tem, 0, 0);
   411       if (NILP (tem) && try_reload)
   412         {
   413           /* The file is newer, we need to reset the pointers.  */
   414           try_reload = reread_doc_file (Fcar_safe (doc));
   415           if (try_reload)
   416             {
   417               try_reload = false;
   418               goto documentation_property;
   419             }
   420         }
   421     }
   422   else if (!STRINGP (tem))
   423     /* Feval protects its argument.  */
   424     tem = Feval (tem, Qnil);
   425 
   426   if (NILP (raw) && STRINGP (tem))
   427     tem = call1 (Qsubstitute_command_keys, tem);
   428   return tem;
   429 }
   430 
   431 /* Scanning the DOC files and placing docstring offsets into functions.  */
   432 
   433 static void
   434 store_function_docstring (Lisp_Object obj, EMACS_INT offset)
   435 {
   436   /* Don't use indirect_function here, or defaliases will apply their
   437      docstrings to the base functions (Bug#2603).  */
   438   Lisp_Object fun = SYMBOLP (obj) ? XSYMBOL (obj)->u.s.function : obj;
   439 
   440   /* The type determines where the docstring is stored.  */
   441 
   442   /* If it's a lisp form, stick it in the form.  */
   443   if (CONSP (fun) && EQ (XCAR (fun), Qmacro))
   444     fun = XCDR (fun);
   445   if (CONSP (fun))
   446     {
   447       Lisp_Object tem = XCAR (fun);
   448       if (EQ (tem, Qlambda) || EQ (tem, Qautoload)
   449           || (EQ (tem, Qclosure) && (fun = XCDR (fun), 1)))
   450         {
   451           tem = Fcdr (Fcdr (fun));
   452           if (CONSP (tem) && FIXNUMP (XCAR (tem)))
   453             /* FIXME: This modifies typically pure hash-cons'd data, so its
   454                correctness is quite delicate.  */
   455             XSETCAR (tem, make_fixnum (offset));
   456         }
   457     }
   458   /* Lisp_Subrs have a slot for it.  */
   459   else if (SUBRP (fun) && !SUBR_NATIVE_COMPILEDP (fun))
   460     {
   461       XSUBR (fun)->doc = offset;
   462     }
   463 
   464   /* Bytecode objects sometimes have slots for it.  */
   465   else if (COMPILEDP (fun))
   466     {
   467       /* This bytecode object must have a slot for the
   468          docstring, since we've found a docstring for it.  */
   469       if (PVSIZE (fun) > COMPILED_DOC_STRING
   470           /* Don't overwrite a non-docstring value placed there,
   471            * such as the symbols used for Oclosures.  */
   472           && VALID_DOCSTRING_P (AREF (fun, COMPILED_DOC_STRING)))
   473         ASET (fun, COMPILED_DOC_STRING, make_fixnum (offset));
   474       else
   475         {
   476           AUTO_STRING (format,
   477                        (PVSIZE (fun) > COMPILED_DOC_STRING
   478                         ? "Docstring slot busy for %s"
   479                         : "No docstring slot for %s"));
   480           CALLN (Fmessage, format,
   481                  (SYMBOLP (obj)
   482                   ? SYMBOL_NAME (obj)
   483                   : build_string ("<anonymous>")));
   484         }
   485     }
   486 }
   487 
   488 
   489 DEFUN ("Snarf-documentation", Fsnarf_documentation, Ssnarf_documentation,
   490        1, 1, 0,
   491        doc: /* Used during Emacs initialization to scan the `etc/DOC...' file.
   492 This searches the `etc/DOC...' file for doc strings and
   493 records them in function and variable definitions.
   494 The function takes one argument, FILENAME, a string;
   495 it specifies the file name (without a directory) of the DOC file.
   496 That file is found in `../etc' now; later, when the dumped Emacs is run,
   497 the same file name is found in the `doc-directory'.  */)
   498   (Lisp_Object filename)
   499 {
   500   int fd;
   501   char buf[1024 + 1];
   502   int filled;
   503   EMACS_INT pos;
   504   Lisp_Object sym;
   505   char *p, *name;
   506   char const *dirname;
   507   ptrdiff_t dirlen;
   508   /* Preloaded defcustoms using custom-initialize-delay are added to
   509      this list, but kept unbound.  See https://debbugs.gnu.org/11565  */
   510   Lisp_Object delayed_init =
   511     find_symbol_value (intern ("custom-delayed-init-variables"));
   512 
   513   if (!CONSP (delayed_init)) delayed_init = Qnil;
   514 
   515   CHECK_STRING (filename);
   516 
   517   if (will_dump_p ())
   518     {
   519       dirname = sibling_etc;
   520       dirlen = sizeof sibling_etc - 1;
   521     }
   522   else
   523     {
   524       CHECK_STRING (Vdoc_directory);
   525       dirname = SSDATA (Vdoc_directory);
   526       dirlen = SBYTES (Vdoc_directory);
   527     }
   528 
   529   specpdl_ref count = SPECPDL_INDEX ();
   530   USE_SAFE_ALLOCA;
   531   name = SAFE_ALLOCA (dirlen + SBYTES (filename) + 1);
   532   lispstpcpy (stpcpy (name, dirname), filename);        /*** Add this line ***/
   533 
   534   /* Vbuild_files is nil when temacs is run, and non-nil after that.  */
   535   if (NILP (Vbuild_files))
   536     {
   537       static char const *const buildobj[] =
   538         {
   539           #include "buildobj.h"
   540         };
   541       int i = ARRAYELTS (buildobj);
   542       while (0 <= --i)
   543         Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
   544       Vbuild_files = Fpurecopy (Vbuild_files);
   545     }
   546 
   547   fd = emacs_open (name, O_RDONLY, 0);
   548   if (fd < 0)
   549     {
   550       int open_errno = errno;
   551       report_file_errno ("Opening doc string file", build_string (name),
   552                          open_errno);
   553     }
   554   record_unwind_protect_int (close_file_unwind, fd);
   555   Vdoc_file_name = filename;
   556   filled = 0;
   557   pos = 0;
   558   while (true)
   559     {
   560       if (filled < 512)
   561         filled += emacs_read_quit (fd, &buf[filled], sizeof buf - 1 - filled);
   562       if (!filled)
   563         break;
   564 
   565       buf[filled] = 0;
   566       char *end = buf + (filled < 512 ? filled : filled - 128);
   567       p = memchr (buf, '\037', end - buf);
   568       /* p points to ^_Ffunctionname\n or ^_Vvarname\n or ^_Sfilename\n.  */
   569       if (p)
   570         {
   571           end = strchr (p, '\n');
   572           if (!end)
   573             error ("DOC file invalid at position %"pI"d", pos);
   574 
   575           /* We used to skip files not in build_files, so that when a
   576              function was defined several times in different files
   577              (typically, once in xterm, once in w32term, ...), we only
   578              paid attention to the relevant one.
   579 
   580              But this meant the doc had to be kept and updated in
   581              multiple files.  Nowadays we keep the doc only in eg xterm.
   582              The (f)boundp checks below ensure we don't report
   583              docs for eg w32-specific items on X.
   584           */
   585 
   586           sym = oblookup (Vobarray, p + 2,
   587                           multibyte_chars_in_text ((unsigned char *) p + 2,
   588                                                    end - p - 2),
   589                           end - p - 2);
   590           /* Ignore docs that start with SKIP.  These mark
   591              placeholders where the real doc is elsewhere.  */
   592           if (SYMBOLP (sym))
   593             {
   594               /* Attach a docstring to a variable?  */
   595               if (p[1] == 'V')
   596                 {
   597                   /* Install file-position as variable-documentation property
   598                      and make it negative for a user-variable
   599                      (doc starts with a `*').  */
   600                   if ((!NILP (Fboundp (sym))
   601                       || !NILP (Fmemq (sym, delayed_init)))
   602                       && strncmp (end, "\nSKIP", 5))
   603                     Fput (sym, Qvariable_documentation,
   604                           make_fixnum ((pos + end + 1 - buf)
   605                                        * (end[1] == '*' ? -1 : 1)));
   606                 }
   607 
   608               /* Attach a docstring to a function?  */
   609               else if (p[1] == 'F')
   610                 {
   611                   if (!NILP (Ffboundp (sym)) && strncmp (end, "\nSKIP", 5))
   612                     store_function_docstring (sym, pos + end + 1 - buf);
   613                 }
   614               else if (p[1] == 'S')
   615                 ; /* Just a source file name boundary marker.  Ignore it.  */
   616 
   617               else
   618                 error ("DOC file invalid at position %"pI"d", pos);
   619             }
   620         }
   621       pos += end - buf;
   622       filled -= end - buf;
   623       memmove (buf, end, filled);
   624     }
   625 
   626   return SAFE_FREE_UNBIND_TO (count, Qnil);
   627 }
   628 
   629 /* Return true if text quoting style should default to quote `like this'.  */
   630 static bool
   631 default_to_grave_quoting_style (void)
   632 {
   633   if (!text_quoting_flag)
   634     return true;
   635   if (! DISP_TABLE_P (Vstandard_display_table))
   636     return false;
   637   Lisp_Object dv = DISP_CHAR_VECTOR (XCHAR_TABLE (Vstandard_display_table),
   638                                      LEFT_SINGLE_QUOTATION_MARK);
   639   return (VECTORP (dv) && ASIZE (dv) == 1
   640           && BASE_EQ (AREF (dv, 0), make_fixnum ('`')));
   641 }
   642 
   643 DEFUN ("text-quoting-style", Ftext_quoting_style,
   644        Stext_quoting_style, 0, 0, 0,
   645        doc: /* Return the current effective text quoting style.
   646 If the variable `text-quoting-style' is `grave', `straight' or
   647 `curve', just return that value.  If it is nil (the default), return
   648 `grave' if curved quotes cannot be displayed (for instance, on a
   649 terminal with no support for these characters), otherwise return
   650 `quote'.  Any other value is treated as `grave'.
   651 
   652 Note that in contrast to the variable `text-quoting-style', this
   653 function will never return nil.  */)
   654   (void)
   655 {
   656   /* Use grave accent and apostrophe `like this'.  */
   657   if (NILP (Vtext_quoting_style)
   658       ? default_to_grave_quoting_style ()
   659       : EQ (Vtext_quoting_style, Qgrave))
   660     return Qgrave;
   661 
   662   /* Use apostrophes 'like this'.  */
   663   else if (EQ (Vtext_quoting_style, Qstraight))
   664     return Qstraight;
   665 
   666   /* Use curved single quotes ‘like this’.  */
   667   else
   668     return Qcurve;
   669 }
   670 
   671 
   672 void
   673 syms_of_doc (void)
   674 {
   675   DEFSYM (Qlisp_directory, "lisp-directory");
   676   DEFSYM (Qsubstitute_command_keys, "substitute-command-keys");
   677   DEFSYM (Qfunction_documentation, "function-documentation");
   678   DEFSYM (Qgrave, "grave");
   679   DEFSYM (Qstraight, "straight");
   680   DEFSYM (Qcurve, "curve");
   681 
   682   DEFVAR_LISP ("internal-doc-file-name", Vdoc_file_name,
   683                doc: /* Name of file containing documentation strings of built-in symbols.  */);
   684   Vdoc_file_name = Qnil;
   685 
   686   DEFVAR_LISP ("build-files", Vbuild_files,
   687                doc: /* A list of files used to build this Emacs binary.  */);
   688   Vbuild_files = Qnil;
   689 
   690   DEFVAR_LISP ("text-quoting-style", Vtext_quoting_style,
   691                doc: /* Style to use for single quotes in help and messages.
   692 
   693 The value of this variable determines substitution of grave accents
   694 and apostrophes in help output (but not for display of Info
   695 manuals) and in functions like `message' and `format-message', but not
   696 in `format'.
   697 
   698 The value should be one of these symbols:
   699   `curve':    quote with curved single quotes ‘like this’.
   700   `straight': quote with straight apostrophes \\='like this\\='.
   701   `grave':    quote with grave accent and apostrophe \\=`like this\\=';
   702               i.e., do not alter the original quote marks.
   703   nil:        like `curve' if curved single quotes are displayable,
   704               and like `grave' otherwise.  This is the default.
   705 
   706 You should never read the value of this variable directly from a Lisp
   707 program.  Use the function `text-quoting-style' instead, as that will
   708 compute the correct value for the current terminal in the nil case.  */);
   709   Vtext_quoting_style = Qnil;
   710 
   711   DEFVAR_BOOL ("internal--text-quoting-flag", text_quoting_flag,
   712                doc: /* If nil, a nil `text-quoting-style' is treated as `grave'.  */);
   713   /* Initialized by ‘main’.  */
   714 
   715   defsubr (&Sdocumentation);
   716   defsubr (&Sdocumentation_property);
   717   defsubr (&Ssnarf_documentation);
   718   defsubr (&Stext_quoting_style);
   719 }

/* [<][>][^][v][top][bottom][index][help] */