初稿: 2018-08-09 Thu 13:58
最終更新日: 2018-12-14 Fri 20:44
ホーム | 文書トップ | 目次

load
ファイルをロードする

  1: DEFUN ("load", Fload, Sload, 1, 5, 0,
  2:        doc: /* Execute a file of Lisp code named FILE.
  3:                First try FILE with `.elc' appended, then try with `.el', then try
  4:                with a system-dependent suffix of dynamic modules (see `load-suffixes'),
  5:                then try FILE unmodified (the exact suffixes in the exact order are
  6:                determined by `load-suffixes').  Environment variable references in
  7:                FILE are replaced with their values by calling `substitute-in-file-name'.
  8:                This function searches the directories in `load-path'.
  9: 
 10:                If optional second arg NOERROR is non-nil,
 11:                report no error if FILE doesn't exist.
 12:                Print messages at start and end of loading unless
 13:                optional third arg NOMESSAGE is non-nil (but `force-load-messages'
 14:                overrides that).
 15:                If optional fourth arg NOSUFFIX is non-nil, don't try adding
 16:                suffixes to the specified name FILE.
 17:                If optional fifth arg MUST-SUFFIX is non-nil, insist on
 18:                the suffix `.elc' or `.el' or the module suffix; don't accept just
 19:                FILE unless it ends in one of those suffixes or includes a directory name.
 20: 
 21:                If NOSUFFIX is nil, then if a file could not be found, try looking for
 22:                a different representation of the file by adding non-empty suffixes to
 23:                its name, before trying another file.  Emacs uses this feature to find
 24:                compressed versions of files when Auto Compression mode is enabled.
 25:                If NOSUFFIX is non-nil, disable this feature.
 26: 
 27:                The suffixes that this function tries out, when NOSUFFIX is nil, are
 28:                given by the return value of `get-load-suffixes' and the values listed
 29:                in `load-file-rep-suffixes'.  If MUST-SUFFIX is non-nil, only the
 30:                return value of `get-load-suffixes' is used, i.e. the file name is
 31:                required to have a non-empty suffix.
 32: 
 33:                When searching suffixes, this function normally stops at the first
 34:                one that exists.  If the option `load-prefer-newer' is non-nil,
 35:                however, it tries all suffixes, and uses whichever file is the newest.
 36: 
 37:                Loading a file records its definitions, and its `provide' and
 38:                `require' calls, in an element of `load-history' whose
 39:                car is the file name loaded.  See `load-history'.
 40: 
 41:                While the file is in the process of being loaded, the variable
 42:                `load-in-progress' is non-nil and the variable `load-file-name'
 43:                is bound to the file's name.
 44: 
 45:                Return t if the file exists and loads successfully.  */)
 46:     (Lisp_Object file, Lisp_Object noerror, Lisp_Object nomessage,
 47:      Lisp_Object nosuffix, Lisp_Object must_suffix) {
 48:     FILE *stream;
 49:     int fd;
 50:     int fd_index;
 51:     ptrdiff_t count = SPECPDL_INDEX();
 52:     Lisp_Object found, efound, hist_file_name;
 53:     /* True means we printed the ".el is newer" message.  */
 54:     bool newer = 0;
 55:     /* True means we are loading a compiled file.  */
 56:     bool compiled = 0;
 57:     Lisp_Object handler;
 58:     bool safe_p = 1;
 59:     const char *fmode = "r" FOPEN_TEXT;
 60:     int version;
 61: 
 62:     CHECK_STRING(file);
 63: 
 64:     /* If file name is magic, call the handler.  */
 65:     /* This shouldn't be necessary any more now that `openp' handles it right.
 66:        handler = Ffind_file_name_handler (file, Qload);
 67:        if (!NILP (handler))
 68:        return call5 (handler, Qload, file, noerror, nomessage, nosuffix); */
 69: 
 70:     /* The presence of this call is the result of a historical accident:
 71:        it used to be in every file-operation and when it got removed
 72:        everywhere, it accidentally stayed here.  Since then, enough people
 73:        supposedly have things like (load "$PROJECT/foo.el") in their .emacs
 74:        that it seemed risky to remove.  */
 75:     if (!NILP(noerror)) {
 76:         file = internal_condition_case_1(Fsubstitute_in_file_name, file, Qt,
 77:                                          load_error_handler);
 78:         if (NILP(file))
 79:             return Qnil;
 80:     } else
 81:         file = Fsubstitute_in_file_name(file);
 82: 
 83:     /* Avoid weird lossage with null string as arg,
 84:        since it would try to load a directory as a Lisp file.  */
 85:     if (SCHARS(file) == 0) {
 86:         fd = -1;
 87:         errno = ENOENT;
 88:     } else {
 89:         Lisp_Object suffixes;
 90:         found = Qnil;
 91: 
 92:         if (!NILP(must_suffix)) {
 93:             /* Don't insist on adding a suffix if FILE already ends with one.  */
 94:             if (suffix_p(file, ".el") || suffix_p(file, ".elc")
 95: #ifdef HAVE_MODULES
 96:                 || suffix_p(file, MODULES_SUFFIX)
 97: #endif
 98:                 )
 99:                 must_suffix = Qnil;
100:             /* Don't insist on adding a suffix
101:                if the argument includes a directory name.  */
102:             else if (!NILP(Ffile_name_directory(file)))
103:                 must_suffix = Qnil;
104:         }
105: 
106:         if (!NILP(nosuffix))
107:             suffixes = Qnil;
108:         else {
109:             suffixes = Fget_load_suffixes();
110:             if (NILP(must_suffix))
111:                 suffixes = CALLN(Fappend, suffixes, Vload_file_rep_suffixes);
112:         }
113: 
114:         fd = openp(Vload_path, file, suffixes, &found, Qnil, load_prefer_newer);
115:     }
116: 
117:     if (fd == -1) {
118:         if (NILP(noerror))
119:             report_file_error("Cannot open load file", file);
120:         return Qnil;
121:     }
122: 
123:     /* Tell startup.el whether or not we found the user's init file.  */
124:     if (EQ(Qt, Vuser_init_file))
125:         Vuser_init_file = found;
126: 
127:     /* If FD is -2, that means openp found a magic file.  */
128:     if (fd == -2) {
129:         if (NILP(Fequal(found, file)))
130:             /* If FOUND is a different file name from FILE,
131:                find its handler even if we have already inhibited
132:                the `load' operation on FILE.  */
133:             handler = Ffind_file_name_handler(found, Qt);
134:         else
135:             handler = Ffind_file_name_handler(found, Qload);
136:         if (!NILP(handler))
137:             return call5(handler, Qload, found, noerror, nomessage, Qt);
138: #ifdef DOS_NT
139:         /* Tramp has to deal with semi-broken packages that prepend
140:            drive letters to remote files.  For that reason, Tramp
141:            catches file operations that test for file existence, which
142:            makes openp think X:/foo.elc files are remote.  However,
143:            Tramp does not catch `load' operations for such files, so we
144:            end up with a nil as the `load' handler above.  If we would
145:            continue with fd = -2, we will behave wrongly, and in
146:            particular try reading a .elc file in the "rt" mode instead
147:            of "rb".  See bug #9311 for the results.  To work around
148:            this, we try to open the file locally, and go with that if it
149:            succeeds.  */
150:         fd = emacs_open(SSDATA(ENCODE_FILE(found)), O_RDONLY, 0);
151:         if (fd == -1)
152:             fd = -2;
153: #endif
154:     }
155: 
156:     if (fd < 0) {
157:         /* Pacify older GCC with --enable-gcc-warnings.  */
158:         IF_LINT(fd_index = 0);
159:     } else {
160:         fd_index = SPECPDL_INDEX();
161:         record_unwind_protect_int(close_file_unwind, fd);
162:     }
163: 
164: #ifdef HAVE_MODULES
165:     if (suffix_p(found, MODULES_SUFFIX))
166:         return unbind_to(count, Fmodule_load(found));
167: #endif
168: 
169:     /* Check if we're stuck in a recursive load cycle.
170: 
171:        2000-09-21: It's not possible to just check for the file loaded
172:        being a member of Vloads_in_progress.  This fails because of the
173:        way the byte compiler currently works; `provide's are not
174:        evaluated, see font-lock.el/jit-lock.el as an example.  This
175:        leads to a certain amount of ``normal'' recursion.
176: 
177:        Also, just loading a file recursively is not always an error in
178:        the general case; the second load may do something different.  */
179: 
180:     int load_count = 0;
181:     Lisp_Object tem;
182:     for (tem = Vloads_in_progress; CONSP(tem); tem = XCDR(tem))
183:         if (!NILP(Fequal(found, XCAR(tem))) && (++load_count > 3))
184:             signal_error("Recursive load", Fcons(found, Vloads_in_progress));
185:     record_unwind_protect(record_load_unwind, Vloads_in_progress);
186:     Vloads_in_progress = Fcons(found, Vloads_in_progress);
187: }
188: 
189: /* All loads are by default dynamic, unless the file itself specifies
190:    otherwise using a file-variable in the first line.  This is bound here
191:    so that it takes effect whether or not we use
192:    Vload_source_file_function.  */
193: specbind(Qlexical_binding, Qnil);
194: 
195: /* Get the name for load-history.  */
196: hist_file_name =
197:     (!NILP(Vpurify_flag)
198:      ? concat2(Ffile_name_directory(file), Ffile_name_nondirectory(found))
199:      : found);
200: 
201: version = -1;
202: 
203: /* Check for the presence of old-style quotes and warn about them.  */
204: specbind(Qold_style_backquotes, Qnil);
205: record_unwind_protect(load_warn_old_style_backquotes, file);
206: 
207: if (suffix_p(found, ".elc") ||
208:     (fd >= 0 && (version = safe_to_load_version(fd)) > 0)) {
209:     /* Load .elc files directly, but not when they are
210:        remote and have no handler!  */
211: 
212:     if (fd != -2) {
213:         struct stat s1, s2;
214:         int result;
215: 
216:         if (version < 0 && !(version = safe_to_load_version(fd))) {
217:             safe_p = 0;
218:             if (!load_dangerous_libraries)
219:                 error("File `%s' was not compiled in Emacs", SDATA(found));
220:             else if (!NILP(nomessage) && !force_load_messages)
221:                 message_with_string("File `%s' not compiled in Emacs", found, 1);
222:         }
223: 
224:         compiled = 1;
225: 
226:         efound = ENCODE_FILE(found);
227:         fmode = "r" FOPEN_BINARY;
228: 
229:         /* openp already checked for newness, no point doing it again.
230:            FIXME would be nice to get a message when openp
231:            ignores suffix order due to load_prefer_newer.  */
232:         if (!load_prefer_newer) {
233:             result = stat(SSDATA(efound), &s1);
234:             if (result == 0) {
235:                 SSET(efound, SBYTES(efound) - 1, 0);
236:                 result = stat(SSDATA(efound), &s2);
237:                 SSET(efound, SBYTES(efound) - 1, 'c');
238:             }
239: 
240:             if (result == 0 &&
241:                 timespec_cmp(get_stat_mtime(&s1), get_stat_mtime(&s2)) < 0) {
242:                 /* Make the progress messages mention that source is newer.  */
243:                 newer = 1;
244: 
245:                 /* If we won't print another message, mention this anyway.  */
246:                 if (!NILP(nomessage) && !force_load_messages) {
247:                     Lisp_Object msg_file;
248:                     msg_file = Fsubstring(found, make_number(0), make_number(-1));
249:                     message_with_string(
250:                                         "Source file `%s' newer than byte-compiled file", msg_file, 1);
251:                 }
252:             }
253:         } /* !load_prefer_newer */
254:     }
255:  } else {
256:     /* We are loading a source file (*.el).  */
257:     if (!NILP(Vload_source_file_function)) {
258:         Lisp_Object val;
259: 
260:         if (fd >= 0) {
261:             emacs_close(fd);
262:             clear_unwind_protect(fd_index);
263:         }
264:         val = call4(Vload_source_file_function, found, hist_file_name,
265:                     NILP(noerror) ? Qnil : Qt,
266:                     (NILP(nomessage) || force_load_messages) ? Qnil : Qt);
267:         return unbind_to(count, val);
268:     }
269:  }
270: 
271: if (fd < 0) {
272:     /* We somehow got here with fd == -2, meaning the file is deemed
273:        to be remote.  Don't even try to reopen the file locally;
274:        just force a failure.  */
275:     stream = NULL;
276:     errno = EINVAL;
277:  } else {
278: #ifdef WINDOWSNT
279:     emacs_close(fd);
280:     clear_unwind_protect(fd_index);
281:     efound = ENCODE_FILE(found);
282:     stream = emacs_fopen(SSDATA(efound), fmode);
283: #else
284:     stream = fdopen(fd, fmode);
285: #endif
286:  }
287: if (!stream)
288:     report_file_error("Opening stdio stream", file);
289: set_unwind_protect_ptr(fd_index, fclose_unwind, stream);
290: 
291: if (!NILP(Vpurify_flag))
292:     Vpreloaded_file_list = Fcons(Fpurecopy(file), Vpreloaded_file_list);
293: 
294: if (NILP(nomessage) || force_load_messages) {
295:     if (!safe_p)
296:         message_with_string(
297:                             "Loading %s (compiled; note unsafe, not compiled in Emacs)...", file,
298:                             1);
299:     else if (!compiled)
300:         message_with_string("Loading %s (source)...", file, 1);
301:     else if (newer)
302:         message_with_string(
303:                             "Loading %s (compiled; note, source file is newer)...", file, 1);
304:     else /* The typical case; compiled file newer than source file.  */
305:         message_with_string("Loading %s...", file, 1);
306:  }
307: 
308: specbind(Qload_file_name, found);
309: specbind(Qinhibit_file_name_operation, Qnil);
310: specbind(Qload_in_progress, Qt);
311: 
312: instream = stream;
313: if (lisp_file_lexically_bound_p(Qget_file_char))
314:     Fset(Qlexical_binding, Qt);
315: 
316: if (!version || version >= 22)
317:     readevalloop(Qget_file_char, stream, hist_file_name, 0, Qnil, Qnil, Qnil,
318:                  Qnil);
319:  else {
320:      /* We can't handle a file which was compiled with
321:         byte-compile-dynamic by older version of Emacs.  */
322:      specbind(Qload_force_doc_strings, Qt);
323:      readevalloop(Qget_emacs_mule_file_char, stream, hist_file_name, 0, Qnil,
324:                   Qnil, Qnil, Qnil);
325:  }
326: unbind_to(count, Qnil);
327: 
328: /* Run any eval-after-load forms for this file.  */
329: if (!NILP(Ffboundp(Qdo_after_load_evaluation)))
330:     call1(Qdo_after_load_evaluation, hist_file_name);
331: 
332: xfree(saved_doc_string);
333: saved_doc_string = 0;
334: saved_doc_string_size = 0;
335: 
336: xfree(prev_saved_doc_string);
337: prev_saved_doc_string = 0;
338: prev_saved_doc_string_size = 0;
339: 
340: if (!noninteractive && (NILP(nomessage) || force_load_messages)) {
341:     if (!safe_p)
342:         message_with_string("Loading %s (compiled; note unsafe, not compiled in Emacs)...done",
343:                             file, 1);
344:     else if (!compiled)
345:         message_with_string("Loading %s (source)...done", file, 1);
346:     else if (newer)
347:         message_with_string(
348:                             "Loading %s (compiled; note, source file is newer)...done", file, 1);
349:     else /* The typical case; compiled file newer than source file.  */
350:         message_with_string("Loading %s...done", file, 1);
351:  }
352: 
353: return Qt;
354: }

日付: 2018-08-09 Thu 13:58

著者: conao

Created: 2018-12-14 Fri 21:04

Validate