Function: Snarf-documentation

Snarf-documentation is a function defined in doc.c.

Signature

(Snarf-documentation FILENAME)

Documentation

Used during Emacs initialization to scan the etc/DOC... file.

This searches the etc/DOC... file for doc strings and records them in function and variable definitions. The function takes one argument, FILENAME, a string; it specifies the file name (without a directory) of the DOC file. That file is found in ../etc now; later, when the dumped Emacs is run, the same file name is found in the doc-directory.

View in manual

Source Code

// Defined in /usr/src/emacs/src/doc.c
{
  int fd;
  char buf[1024 + 1];
  int filled;
  EMACS_INT pos;
  Lisp_Object sym;
  char *p, *name;
  char const *dirname;
  ptrdiff_t dirlen;
  /* Preloaded defcustoms using custom-initialize-delay are added to
     this list, but kept unbound.  See https://debbugs.gnu.org/11565  */
  Lisp_Object delayed_init =
    find_symbol_value (intern ("custom-delayed-init-variables"));

  if (!CONSP (delayed_init)) delayed_init = Qnil;

  CHECK_STRING (filename);

  if (will_dump_p ())
    {
      dirname = sibling_etc;
      dirlen = sizeof sibling_etc - 1;
    }
  else
    {
      CHECK_STRING (Vdoc_directory);
      dirname = SSDATA (Vdoc_directory);
      dirlen = SBYTES (Vdoc_directory);
    }

  specpdl_ref count = SPECPDL_INDEX ();
  USE_SAFE_ALLOCA;
  name = SAFE_ALLOCA (dirlen + SBYTES (filename) + 1);
  lispstpcpy (stpcpy (name, dirname), filename);        /*** Add this line ***/

  /* Vbuild_files is nil when temacs is run, and non-nil after that.  */
  if (NILP (Vbuild_files))
    {
      static char const *const buildobj[] =
	{
	  #include "buildobj.h"
	};
      int i = ARRAYELTS (buildobj);
      while (0 <= --i)
	Vbuild_files = Fcons (build_string (buildobj[i]), Vbuild_files);
      Vbuild_files = Fpurecopy (Vbuild_files);
    }

  fd = emacs_open (name, O_RDONLY, 0);
  if (fd < 0)
    {
      int open_errno = errno;
      report_file_errno ("Opening doc string file", build_string (name),
			 open_errno);
    }
  record_unwind_protect_int (close_file_unwind, fd);
  Vdoc_file_name = filename;
  filled = 0;
  pos = 0;
  while (true)
    {
      if (filled < 512)
	filled += emacs_read_quit (fd, &buf[filled], sizeof buf - 1 - filled);
      if (!filled)
	break;

      buf[filled] = 0;
      char *end = buf + (filled < 512 ? filled : filled - 128);
      p = memchr (buf, '\037', end - buf);
      /* p points to ^_Ffunctionname\n or ^_Vvarname\n or ^_Sfilename\n.  */
      if (p)
	{
	  end = strchr (p, '\n');
	  if (!end)
	    error ("DOC file invalid at position %"pI"d", pos);

	  /* We used to skip files not in build_files, so that when a
	     function was defined several times in different files
	     (typically, once in xterm, once in w32term, ...), we only
	     paid attention to the relevant one.

	     But this meant the doc had to be kept and updated in
	     multiple files.  Nowadays we keep the doc only in eg xterm.
	     The (f)boundp checks below ensure we don't report
	     docs for eg w32-specific items on X.
	  */

	  sym = oblookup (Vobarray, p + 2,
			  multibyte_chars_in_text ((unsigned char *) p + 2,
						   end - p - 2),
			  end - p - 2);
          /* Ignore docs that start with SKIP.  These mark
             placeholders where the real doc is elsewhere.  */
	  if (SYMBOLP (sym))
	    {
	      /* Attach a docstring to a variable?  */
	      if (p[1] == 'V')
		{
		  /* Install file-position as variable-documentation property
		     and make it negative for a user-variable
		     (doc starts with a `*').  */
                  if ((!NILP (Fboundp (sym))
                      || !NILP (Fmemq (sym, delayed_init)))
                      && strncmp (end, "\nSKIP", 5))
                    Fput (sym, Qvariable_documentation,
                          make_fixnum ((pos + end + 1 - buf)
                                       * (end[1] == '*' ? -1 : 1)));
		}

	      /* Attach a docstring to a function?  */
	      else if (p[1] == 'F')
                {
                  if (!NILP (Ffboundp (sym)) && strncmp (end, "\nSKIP", 5))
                    store_function_docstring (sym, pos + end + 1 - buf);
                }
	      else if (p[1] == 'S')
		; /* Just a source file name boundary marker.  Ignore it.  */

	      else
		error ("DOC file invalid at position %"pI"d", pos);
	    }
	}
      pos += end - buf;
      filled -= end - buf;
      memmove (buf, end, filled);
    }

  return SAFE_FREE_UNBIND_TO (count, Qnil);
}