1%% =====================================================================
2%% Licensed under the Apache License, Version 2.0 (the "License"); you may
3%% not use this file except in compliance with the License. You may obtain
4%% a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>
5%%
6%% Unless required by applicable law or agreed to in writing, software
7%% distributed under the License is distributed on an "AS IS" BASIS,
8%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9%% See the License for the specific language governing permissions and
10%% limitations under the License.
11%%
12%% Alternatively, you may use this file under the terms of the GNU Lesser
13%% General Public License (the "LGPL") as published by the Free Software
14%% Foundation; either version 2.1, or (at your option) any later version.
15%% If you wish to allow use of your version of this file only under the
16%% terms of the LGPL, you should delete the provisions above and replace
17%% them with the notice and other provisions required by the LGPL; see
18%% <http://www.gnu.org/licenses/>. If you do not delete the provisions
19%% above, a recipient may use your version of this file under the terms of
20%% either the Apache License or the LGPL.
21%%
22%% @copyright 2001-2003 Richard Carlsson
23%% @author Richard Carlsson <carlsson.richard@gmail.com>
24%% @see edoc
25%% @end
26%% =====================================================================
27
28%% @doc Utility functions for EDoc.
29
30-module(edoc_lib).
31
32-export([count/2, lines/1, split_at/2, split_at_stop/1,
33	 split_at_space/1, filename/1, transpose/1, segment/2,
34	 get_first_sentence/1, is_space/1, strip_space/1, parse_expr/2,
35	 parse_contact/2, escape_uri/1, join_uri/2,
36	 is_name/1, to_label/1, find_doc_dirs/0, find_sources/2,
37	 find_file/2, try_subdir/2, unique/1,
38	 write_file/3, write_file/4, write_info_file/3,
39	 read_info_file/1, get_doc_env/1, get_doc_env/3, copy_file/2,
40	 run_doclet/2, run_layout/2,
41	 simplify_path/1, timestr/1, datestr/1, read_encoding/2,
42	 infer_module_app/1]).
43
44-import(edoc_report, [report/2, warning/2]).
45
46-include("edoc.hrl").
47-include_lib("xmerl/include/xmerl.hrl").
48
49-type filename() :: file:filename().
50-type proplist() :: proplists:proplist().
51
52-define(FILE_BASE, "/").
53
54
55%% ---------------------------------------------------------------------
56%% List and string utilities
57
58%% @private
59timestr({H,M,Sec}) ->
60    lists:flatten(io_lib:fwrite("~2.2.0w:~2.2.0w:~2.2.0w",[H,M,Sec])).
61
62%% @private
63datestr({Y,M,D}) ->
64    Ms = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
65	  "Oct", "Nov", "Dec"],
66    lists:flatten(io_lib:fwrite("~s ~w ~w",[lists:nth(M, Ms),D,Y])).
67
68%% @private
69read_encoding(File, Options) ->
70    case epp:read_encoding(File, Options) of
71        none -> epp:default_encoding();
72        Encoding -> Encoding
73    end.
74
75%% @doc Infer application containing the given module.
76%%
77%% It's expected that modules which are not preloaded
78%% and don't match the  `<app>/ebin/<mod>.beam' path pattern
79%% will NOT have an app name inferred properly.
80%% `no_app' is returned in such cases.
81-spec infer_module_app(module()) -> no_app | {app, atom()}.
82infer_module_app(Mod) ->
83    case code:which(Mod) of
84	ModPath when is_list(ModPath) ->
85	    case lists:reverse(string:tokens(ModPath, "/")) of
86		[_BeamFile, "ebin", AppVer | _] ->
87		    [App | _] = string:tokens(AppVer, "-"),
88		    {app, list_to_atom(App)};
89		_ ->
90		    no_app
91	    end;
92	preloaded ->
93	    {app, erts};
94	_ ->
95	    no_app
96    end.
97
98%% @private
99count(X, Xs) ->
100    count(X, Xs, 0).
101
102count(X, [X | Xs], N) ->
103    count(X, Xs, N + 1);
104count(X, [_ | Xs], N) ->
105    count(X, Xs, N);
106count(_X, [], N) ->
107    N.
108
109%% @private
110lines(Cs) ->
111    lines(Cs, [], []).
112
113lines([$\n | Cs], As, Ls) ->
114    lines(Cs, [], [lists:reverse(As) | Ls]);
115lines([C | Cs], As, Ls) ->
116    lines(Cs, [C | As], Ls);
117lines([], As, Ls) ->
118    lists:reverse([lists:reverse(As) | Ls]).
119
120%% @private
121split_at(Cs, K) ->
122    split_at(Cs, K, []).
123
124split_at([K | Cs], K, As) ->
125    {lists:reverse(As), Cs};
126split_at([C | Cs], K, As) ->
127    split_at(Cs, K, [C | As]);
128split_at([], _K, As) ->
129    {lists:reverse(As), []}.
130
131%% @private
132split_at_stop(Cs) ->
133    split_at_stop(Cs, []).
134
135split_at_stop([$., $\s | Cs], As) ->
136    {lists:reverse(As), Cs};
137split_at_stop([$., $\t | Cs], As) ->
138    {lists:reverse(As), Cs};
139split_at_stop([$., $\n | Cs], As) ->
140    {lists:reverse(As), Cs};
141split_at_stop([$.], As) ->
142    {lists:reverse(As), []};
143split_at_stop([C | Cs], As) ->
144    split_at_stop(Cs, [C | As]);
145split_at_stop([], As) ->
146    {lists:reverse(As), []}.
147
148%% @private
149split_at_space(Cs) ->
150    split_at_space(Cs, []).
151
152split_at_space([$\s | Cs], As) ->
153    {lists:reverse(As), Cs};
154split_at_space([$\t | Cs], As) ->
155    {lists:reverse(As), Cs};
156split_at_space([$\n | Cs], As) ->
157    {lists:reverse(As), Cs};
158split_at_space([C | Cs], As) ->
159    split_at_space(Cs, [C | As]);
160split_at_space([], As) ->
161    {lists:reverse(As), []}.
162
163%% @private
164is_space([$\s | Cs]) -> is_space(Cs);
165is_space([$\t | Cs]) -> is_space(Cs);
166is_space([$\n | Cs]) -> is_space(Cs);
167is_space([_C | _Cs]) -> false;
168is_space([]) -> true.
169
170%% @private
171strip_space([$\s | Cs]) -> strip_space(Cs);
172strip_space([$\t | Cs]) -> strip_space(Cs);
173strip_space([$\n | Cs]) -> strip_space(Cs);
174strip_space(Cs) -> Cs.
175
176%% @private
177segment(Es, N) ->
178    segment(Es, [], [], 0, N).
179
180segment([E | Es], As, Cs, N, M) when N < M ->
181    segment(Es, [E | As], Cs, N + 1, M);
182segment([_ | _] = Es, As, Cs, _N, M) ->
183    segment(Es, [], [lists:reverse(As) | Cs], 0, M);
184segment([], [], Cs, _N, _M) ->
185    lists:reverse(Cs);
186segment([], As, Cs, _N, _M) ->
187    lists:reverse([lists:reverse(As) | Cs]).
188
189%% @private
190transpose([]) -> [];
191transpose([[] | Xss]) -> transpose(Xss);
192transpose([[X | Xs] | Xss]) ->
193    [[X | [H || [H | _T] <- Xss]]
194     | transpose([Xs | [T || [_H | T] <- Xss]])].
195
196%% Note that the parser will not produce two adjacent text segments;
197%% thus, if a text segment ends with a period character, it marks the
198%% end of the summary sentence only if it is also the last segment in
199%% the list, or is followed by a 'p' or 'br' ("whitespace") element.
200
201%% @private
202get_first_sentence([#xmlElement{name = p, content = Es} | _]) ->
203    %% Descend into initial paragraph.
204    get_first_sentence_1(Es);
205get_first_sentence(Es) ->
206    get_first_sentence_1(Es).
207
208get_first_sentence_1([E = #xmlText{value = Txt} | Es]) ->
209    Last = case Es of
210	       [#xmlElement{name = p} | _] -> true;
211	       [#xmlElement{name = br} | _] -> true;
212	       [] -> true;
213	       _ -> false
214	   end,
215    case end_of_sentence(Txt, Last) of
216	{value, Txt1} ->
217	    [E#xmlText{value = Txt1}];
218	none ->
219	    [E | get_first_sentence_1(Es)]
220    end;
221get_first_sentence_1([E | Es]) ->
222    % Skip non-text segments - don't descend further
223    [E | get_first_sentence_1(Es)];
224get_first_sentence_1([]) ->
225    [].
226
227end_of_sentence(Cs, Last) ->
228    end_of_sentence(Cs, Last, []).
229
230%% We detect '.' and '!' as end-of-sentence markers.
231
232end_of_sentence([C=$., $\s | _], _, As) ->
233    end_of_sentence_1(C, true, As);
234end_of_sentence([C=$., $\t | _], _, As) ->
235    end_of_sentence_1(C, true, As);
236end_of_sentence([C=$., $\n | _], _, As) ->
237    end_of_sentence_1(C, true, As);
238end_of_sentence([C=$.], Last, As) ->
239    end_of_sentence_1(C, Last, As);
240end_of_sentence([C=$!, $\s | _], _, As) ->
241    end_of_sentence_1(C, true, As);
242end_of_sentence([C=$!, $\t | _], _, As) ->
243    end_of_sentence_1(C, true, As);
244end_of_sentence([C=$!, $\n | _], _, As) ->
245    end_of_sentence_1(C, true, As);
246end_of_sentence([C=$!], Last, As) ->
247    end_of_sentence_1(C, Last, As);
248end_of_sentence([C | Cs], Last, As) ->
249    end_of_sentence(Cs, Last, [C | As]);
250end_of_sentence([], Last, As) ->
251    end_of_sentence_1($., Last, strip_space(As)).  % add a '.'
252
253end_of_sentence_1(C, true, As) ->
254    {value, lists:reverse([C | As])};
255end_of_sentence_1(_, false, _) ->
256    none.
257
258%% For handling ISO 8859-1 (Latin-1) we use the following information:
259%%
260%% 000 - 037	NUL - US	control
261%% 040 - 057	SPC - /		punctuation
262%% 060 - 071	0 - 9		digit
263%% 072 - 100	: - @		punctuation
264%% 101 - 132	A - Z		uppercase
265%% 133 - 140	[ - `		punctuation
266%% 141 - 172	a - z		lowercase
267%% 173 - 176	{ - ~		punctuation
268%% 177		DEL		control
269%% 200 - 237			control
270%% 240 - 277	NBSP - ¿	punctuation
271%% 300 - 326	À - Ö		uppercase
272%% 327		×		punctuation
273%% 330 - 336	Ø - Þ		uppercase
274%% 337 - 366	ß - ö		lowercase
275%% 367		÷		punctuation
276%% 370 - 377	ø - ÿ		lowercase
277
278%% Names must begin with a lowercase letter and contain only
279%% alphanumerics and underscores.
280
281%% @private
282is_name([C | Cs]) when C >= $a, C =< $z ->
283    is_name_1(Cs);
284is_name([C | Cs]) when C >= $\337, C =< $\377, C =/= $\367 ->
285    is_name_1(Cs);
286is_name(_) -> false.
287
288is_name_1([C | Cs]) when C >= $a, C =< $z ->
289    is_name_1(Cs);
290is_name_1([C | Cs]) when C >= $A, C =< $Z ->
291    is_name_1(Cs);
292is_name_1([C | Cs]) when C >= $0, C =< $9 ->
293    is_name_1(Cs);
294is_name_1([C | Cs]) when C >= $\300, C =< $\377, C =/= $\327, C =/= $\367 ->
295    is_name_1(Cs);
296is_name_1([$_ | Cs]) ->
297    is_name_1(Cs);
298is_name_1([]) -> true;
299is_name_1(_) -> false.
300
301%% @private
302unique([X | Xs]) -> [X | unique(Xs, X)];
303unique([]) -> [].
304
305unique([X | Xs], X) -> unique(Xs, X);
306unique([X | Xs], _) -> [X | unique(Xs, X)];
307unique([], _) -> [].
308
309
310%% ---------------------------------------------------------------------
311%% Parsing utilities
312
313%% @doc EDoc Erlang expression parsing. For parsing things like the
314%% content of <a href="overview-summary.html#ftag-equiv">`@equiv'</a>
315%% tags, and strings denoting file names, e.g. in @headerfile. Also used
316%% by {@link edoc_run}.
317%% @private
318
319parse_expr(S, L) ->
320    case erl_scan:string(S ++ ".", L) of
321	{ok, Ts, _} ->
322	    case erl_parse:parse_exprs(Ts) of
323		{ok, [Expr]} ->
324		    Expr;
325 		{error, {999999, erl_parse, _}} ->
326 		    throw_error(eof, L);
327 		{error, E} ->
328 		    throw_error(E, L)
329	    end;
330	{error, E, _} ->
331	    throw_error(E, L)
332    end.
333
334
335-record(info, {name = "",
336	       email = "",
337	       uri = ""}).
338
339%-type info() :: #info{name :: string(),
340%                      email :: string(),
341%                      uri :: string()}.
342
343%% @doc EDoc "contact information" parsing. This is the type of the
344%% content in e.g.
345%% <a href="overview-summary.html#mtag-author">`@author'</a> tags.
346%% @private
347
348parse_contact(S, L) ->
349    I = scan_name(S, L, #info{}, []),
350    {I#info.name, I#info.email, I#info.uri}.
351
352%% The name is taken as the first non-whitespace-only string before,
353%% between, or following the e-mail/URI sections. Subsequent text that
354%% is not e/mail or URI is ignored.
355
356scan_name([$< | Cs], L, I, As) ->
357    case I#info.email of
358	"" ->
359	    {Cs1, I1} = scan_email(Cs, L, set_name(I, As), []),
360	    scan_name(Cs1, L, I1, []);
361	_ ->
362	    throw_error("multiple '<...>' sections.", L)
363    end;
364scan_name([$[ | Cs], L, I, As) ->
365    case I#info.uri of
366	"" ->
367	    {Cs1, I1} = scan_uri(Cs, L, set_name(I, As), []),
368	    scan_name(Cs1, L, I1, []);
369	_ ->
370	    throw_error("multiple '[...]' sections.", L)
371    end;
372scan_name([$\n | Cs], L, I, As) ->
373    scan_name(Cs, L + 1, I, [$\n | As]);
374scan_name([C | Cs], L, I, As) ->
375    scan_name(Cs, L, I, [C | As]);
376scan_name([], _L, I, As) ->
377    set_name(I, As).
378
379scan_uri([$] | Cs], _L, I, As) ->
380    {Cs, I#info{uri = strip_and_reverse(As)}};
381scan_uri([$\n | Cs], L, I, As) ->
382    scan_uri(Cs, L + 1, I, [$\n | As]);
383scan_uri([C | Cs], L, I, As) ->
384    scan_uri(Cs, L, I, [C | As]);
385scan_uri([], L, _I, _As) ->
386    throw_error({missing, $]}, L).
387
388scan_email([$> | Cs], _L, I, As) ->
389    {Cs, I#info{email = strip_and_reverse(As)}};
390scan_email([$\n | Cs], L, I, As) ->
391    scan_email(Cs, L + 1, I, [$\n | As]);
392scan_email([C | Cs], L, I, As) ->
393    scan_email(Cs, L, I, [C | As]);
394scan_email([], L, _I, _As) ->
395    throw_error({missing, $>}, L).
396
397set_name(I, As) ->
398    case I#info.name of
399	"" -> I#info{name = strip_and_reverse(As)};
400	_ -> I
401    end.
402
403strip_and_reverse(As) ->
404    edoc_lib:strip_space(lists:reverse(edoc_lib:strip_space(As))).
405
406
407%% ---------------------------------------------------------------------
408%% URI and Internet
409
410%% This is a conservative URI escaping, which escapes anything that may
411%% not appear in an NMTOKEN ([a-zA-Z0-9]|'.'|'-'|'_'), including ':'.
412%% Characters are first encoded in UTF-8.
413%%
414%% Note that this should *not* be applied to complete URI, but only to
415%% segments that may need escaping, when forming a complete URI.
416%%
417%% TODO: general utf-8 encoding for all of Unicode (0-16#10ffff)
418
419%% @private
420escape_uri([C | Cs]) when C >= $a, C =< $z ->
421    [C | escape_uri(Cs)];
422escape_uri([C | Cs]) when C >= $A, C =< $Z ->
423    [C | escape_uri(Cs)];
424escape_uri([C | Cs]) when C >= $0, C =< $9 ->
425    [C | escape_uri(Cs)];
426escape_uri([C = $. | Cs]) ->
427    [C | escape_uri(Cs)];
428escape_uri([C = $- | Cs]) ->
429    [C | escape_uri(Cs)];
430escape_uri([C = $_ | Cs]) ->
431    [C | escape_uri(Cs)];
432escape_uri([C | Cs]) when C > 16#7f ->
433    %% This assumes that characters are at most 16 bits wide.
434    escape_byte(((C band 16#c0) bsr 6) + 16#c0)
435	++ escape_byte(C band 16#3f + 16#80)
436	++ escape_uri(Cs);
437escape_uri([C | Cs]) ->
438    escape_byte(C) ++ escape_uri(Cs);
439escape_uri([]) ->
440    [].
441
442escape_byte(C) when C >= 0, C =< 255 ->
443    [$%, hex_digit(C bsr 4), hex_digit(C band 15)].
444
445hex_digit(N) when N >= 0, N =< 9 ->
446    N + $0;
447hex_digit(N) when N > 9, N =< 15 ->
448    N + $a - 10.
449
450% utf8([C | Cs]) when C > 16#7f ->
451%     [((C band 16#c0) bsr 6) + 16#c0, C band 16#3f ++ 16#80 | utf8(Cs)];
452% utf8([C | Cs]) ->
453%     [C | utf8(Cs)];
454% utf8([]) ->
455%     [].
456
457%% Please note that URI are *not* file names. Don't use the stdlib
458%% 'filename' module for operations on (any parts of) URI.
459
460%% @private
461join_uri(Base, "") ->
462    Base;
463join_uri("", Path) ->
464    Path;
465join_uri(Base, Path) ->
466    Base ++ "/" ++ Path.
467
468%% @private
469to_label([$\s | Cs]) ->
470    to_label(Cs);
471to_label([$\t | Cs]) ->
472    to_label(Cs);
473to_label([$\n | Cs]) ->
474    to_label(Cs);
475to_label([]) ->
476    [];
477to_label(Cs) ->
478    to_label_1(Cs).
479
480to_label_1([$\s | Cs]) ->
481    to_label_2([$\s | Cs]);
482to_label_1([$\t | Cs]) ->
483    to_label_2([$\s | Cs]);
484to_label_1([$\n | Cs]) ->
485    to_label_2([$\s | Cs]);
486to_label_1([C | Cs]) ->
487    [C | to_label_1(Cs)];
488to_label_1([]) ->
489    [].
490
491to_label_2(Cs) ->
492    case to_label(Cs) of
493	[] -> [];
494	Cs1 -> [$_ | Cs1]
495    end.
496
497
498%% ---------------------------------------------------------------------
499%% Files
500
501%% @private
502filename([C | T]) when is_integer(C), C > 0 ->
503    [C | filename(T)];
504filename([H|T]) ->
505    filename(H) ++ filename(T);
506filename([]) ->
507    [];
508filename(N) when is_atom(N) ->
509    atom_to_list(N);
510filename(N) ->
511    report("bad filename: `~tP'.", [N, 25]),
512    exit(error).
513
514%% @private
515copy_file(From, To) ->
516    case file:copy(From, To) of
517	{ok, _} -> ok;
518	{error, R} ->
519	    R1 = file:format_error(R),
520	    report("error copying '~ts' to '~ts': ~ts.", [From, To, R1]),
521	    exit(error)
522    end.
523
524list_dir(Dir, Error) ->
525    case file:list_dir(Dir) of
526	{ok, Fs} ->
527	    Fs;
528	{error, R} ->
529	    F = case Error of
530		    %% true ->
531		    %%	fun (S, As) -> report(S, As), exit(error) end;
532		    false ->
533			fun (S, As) -> warning(S, As), [] end
534		end,
535	    R1 = file:format_error(R),
536	    F("could not read directory '~ts': ~ts.", [filename(Dir), R1])
537    end.
538
539%% @private
540simplify_path(P) ->
541    case filename:basename(P) of
542	"." ->
543	    simplify_path(filename:dirname(P));
544	".." ->
545	    simplify_path(filename:dirname(filename:dirname(P)));
546	_ ->
547	    P
548    end.
549
550%% The directories From and To are assumed to exist.
551
552%% copy_dir(From, To) ->
553%%     Es = list_dir(From, true),    % error if listing fails
554%%     lists:foreach(fun (E) -> copy_dir(From, To, E) end, Es).
555
556%% copy_dir(From, To, Entry) ->
557%%     From1 = filename:join(From, Entry),
558%%     To1 = filename:join(To, Entry),
559%%     case filelib:is_dir(From1) of
560%% 	true ->
561%% 	    make_dir(To1),
562%% 	    copy_dir(From1, To1);
563%% 	false ->
564%% 	    copy_file(From1, To1)
565%%     end.
566
567%% make_dir(Dir) ->
568%%     case file:make_dir(Dir) of
569%% 	ok -> ok;
570%% 	{error, R} ->
571%% 	    R1 = file:format_error(R),
572%% 	    report("cannot create directory '~ts': ~ts.", [Dir, R1]),
573%% 	    exit(error)
574%%     end.
575
576%% @private
577try_subdir(Dir, Subdir) ->
578    D = filename:join(Dir, Subdir),
579    case filelib:is_dir(D) of
580	true -> D;
581	false -> Dir
582    end.
583
584%% @doc Write the given `Text' to the file named by `Name' in directory
585%% `Dir'. If the target directory does not exist, it will be created.
586%% @private
587
588-spec write_file(Text, Dir, Name) -> ok when
589      Text :: unicode:chardata(),
590      Dir :: filename(),
591      Name :: filename().
592write_file(Text, Dir, Name) ->
593    write_file(Text, Dir, Name, [{encoding,latin1}]).
594
595write_file(Text, Dir, Name, Options) ->
596    File = filename:join([Dir, Name]),
597    ok = filelib:ensure_dir(File),
598    case file:open(File, [write] ++ Options) of
599	{ok, FD} ->
600	    io:put_chars(FD, Text),
601	    ok = file:close(FD);
602	{error, R} ->
603	    R1 = file:format_error(R),
604	    report("could not write file '~ts': ~ts.", [File, R1]),
605	    exit(error)
606    end.
607
608%% @private
609write_info_file(App, Modules, Dir) ->
610    Ts = [{modules, Modules}],
611    Ts1 = if App =:= no_app -> Ts;
612	     true -> [{application, App} | Ts]
613	  end,
614    S0 = [io_lib:fwrite("~p.\n", [T]) || T <- Ts1],
615    S = ["%% encoding: UTF-8\n" | S0],
616    write_file(S, Dir, ?INFO_FILE, [{encoding,unicode}]).
617
618%% @doc Reads text from the file named by `Name'.
619
620-spec read_file(filename()) -> {ok, string()} | {error, term()}.
621read_file(File) ->
622    case file:read_file(File) of
623	{ok, Bin} ->
624            Enc = edoc_lib:read_encoding(File, []),
625            case catch unicode:characters_to_list(Bin, Enc) of
626                String when is_list(String) ->
627                    {ok, String};
628                _ ->
629                    {error, invalid_unicode}
630            end;
631	{error, Reason} -> {error, Reason}
632    end.
633
634
635%% ---------------------------------------------------------------------
636%% Info files
637
638info_file_data(Ts) ->
639    App = proplists:get_value(application, Ts, no_app),
640    Ms = proplists:append_values(modules, Ts),
641    {App, Ms}.
642
643%% Local file access - don't complain if file does not exist.
644
645%% @private
646read_info_file(Dir) ->
647    File = filename:join(Dir, ?INFO_FILE),
648    case filelib:is_file(File) of
649	true ->
650	    case read_file(File) of
651		{ok, Text} ->
652		    parse_info_file(Text, File);
653		{error, R} ->
654		    R1 = file:format_error(R),
655		    warning("could not read '~ts': ~ts.", [File, R1]),
656		    {no_app, []}
657	    end;
658	false ->
659	    {no_app, []}
660    end.
661
662parse_info_file(Text, Name) ->
663    case parse_terms(Text) of
664	{ok, Vs} ->
665	    info_file_data(Vs);
666	{error, eof} ->
667	    warning("unexpected end of file in '~ts'.", [Name]),
668	    {no_app, []};
669	{error, {_Line,Module,R}} ->
670	    warning("~ts: ~ts.", [Module:format_error(R), Name]),
671	    {no_app, []}
672    end.
673
674parse_terms(Text) ->
675    case erl_scan:string(Text) of
676	{ok, Ts, _Line} ->
677	    parse_terms_1(Ts, [], []);
678	{error, R, _Line} ->
679	    {error, R}
680    end.
681
682parse_terms_1([T={dot, _L} | Ts], As, Vs) ->
683    case erl_parse:parse_term(lists:reverse([T | As])) of
684	{ok, V} ->
685	    parse_terms_1(Ts, [], [V | Vs]);
686	{error, R} ->
687	    {error, R}
688    end;
689parse_terms_1([T | Ts], As, Vs) ->
690    parse_terms_1(Ts, [T | As], Vs);
691parse_terms_1([], [], Vs) ->
692    {ok, lists:reverse(Vs)};
693parse_terms_1([], _As, _Vs) ->
694    {error, eof}.
695
696
697%% ---------------------------------------------------------------------
698%% Source files
699
700%% @doc See {@link edoc:run/2} for a description of the options
701%% `subpackages', `source_suffix'.
702%% @private
703
704%% NEW-OPTIONS: subpackages, source_suffix
705%% DEFER-OPTIONS: edoc:run/2
706
707find_sources(Path, Opts) ->
708    Rec = proplists:get_bool(subpackages, Opts),
709    Ext = proplists:get_value(source_suffix, Opts, ?DEFAULT_SOURCE_SUFFIX),
710    find_sources(Path, Rec, Ext, Opts).
711
712find_sources(Path, Rec, Ext, _Opts) ->
713    lists:flatten(find_sources_1(Path, Rec, Ext)).
714
715find_sources_1([P | Ps], Rec, Ext) ->
716    Dir = P,
717    Fs1 = find_sources_1(Ps, Rec, Ext),
718    case filelib:is_dir(Dir) of
719	true ->
720	    [find_sources_2(Dir, Rec, Ext) | Fs1];
721	false ->
722	    Fs1
723    end;
724find_sources_1([], _Rec, _Ext) ->
725    [].
726
727find_sources_2(Dir, Rec, Ext) ->
728	Es = list_dir(Dir, false),    % just warn if listing fails
729	Es1 = [{E, Dir} || E <- Es, is_source_file(E, Ext)],
730	case Rec of
731		true ->
732			[find_sources_3(Es, Dir, Rec, Ext) | Es1];
733		false ->
734			Es1
735	end.
736
737find_sources_3(Es, Dir, Rec, Ext) ->
738    [find_sources_2(filename:join(Dir, E),
739		    Rec, Ext)
740     || E <- Es, is_source_dir(E, Dir)].
741
742is_source_file(Name, Ext) ->
743    (filename:extension(Name) == Ext)
744	andalso is_name(filename:rootname(Name, Ext)).
745
746is_source_dir(Name, Dir) ->
747    filelib:is_dir(filename:join(Dir, Name)).
748
749%% @private
750find_file([P | Ps], Name) ->
751    File = filename:join(P, Name),
752    case filelib:is_file(File) of
753	true ->
754	    File;
755	false ->
756	    find_file(Ps, Name)
757    end;
758find_file([], _Name) ->
759    "".
760
761%% @private
762find_doc_dirs() ->
763    find_doc_dirs(code:get_path()).
764
765find_doc_dirs([P0 | Ps]) ->
766    P = filename:absname(P0),
767    P1 = case filename:basename(P) of
768	     ?EBIN_DIR ->
769		 filename:dirname(P);
770	     _ ->
771		 P
772	 end,
773    Dir = try_subdir(P1, ?EDOC_DIR),
774    File = filename:join(Dir, ?INFO_FILE),
775    case filelib:is_file(File) of
776	true ->
777	    [Dir | find_doc_dirs(Ps)];
778	false ->
779	    find_doc_dirs(Ps)
780    end;
781find_doc_dirs([]) ->
782    [].
783
784%% All names with "internal linkage" are mapped to the empty string, so
785%% that relative references will be created. For apps, the empty string
786%% implies that we use the default app-path.
787
788%% NEW-OPTIONS: doc_path
789%% DEFER-OPTIONS: get_doc_env/3
790
791get_doc_links(App, Modules, Opts) ->
792    Path = proplists:append_values(doc_path, Opts) ++ find_doc_dirs(),
793    Ds = [{P, read_info_file(P)} || P <- Path],
794    Ds1 = [{"", {App, Modules}} | Ds],
795    D = dict:new(),
796    make_links(Ds1, D, D).
797
798make_links([{Dir, {App, Ms}} | Ds], A, M) ->
799    A1 = if App == no_app -> A;
800	    true -> add_new(App, Dir, A)
801	 end,
802    F = fun (K, D) -> add_new(K, Dir, D) end,
803    M1 = lists:foldl(F, M, Ms),
804    make_links(Ds, A1, M1);
805make_links([], A,  M) ->
806    F = fun (D) ->
807		fun (K) ->
808			case dict:find(K, D) of
809			    {ok, V} -> V;
810			    error -> ""
811			end
812		end
813	end,
814    {F(A), F(M)}.
815
816add_new(K, V, D) ->
817    case dict:is_key(K, D) of
818	true ->
819	    D;
820	false ->
821	    dict:store(K, V, D)
822    end.
823
824%% @equiv get_doc_env([], [], Opts)
825%% @private
826
827-spec get_doc_env(proplist()) -> edoc:env().
828get_doc_env(Opts) ->
829    get_doc_env(no_app, [], Opts).
830
831%% @doc Creates an environment data structure used by parts of EDoc for
832%% generating references, etc. See {@link edoc:run/2} for a description
833%% of the options `file_suffix', `app_default' and `doc_path'.
834%%
835%% @see edoc_extract:source/4
836%% @see edoc:get_doc/3
837
838%% NEW-OPTIONS: file_suffix, app_default
839%% INHERIT-OPTIONS: get_doc_links/4
840%% DEFER-OPTIONS: edoc:run/2
841
842-spec get_doc_env(App, Modules, Options) -> edoc:env() when
843      App :: atom() | no_app,
844      Modules :: [module()],
845      Options :: proplist().
846get_doc_env(App, Modules, Opts) ->
847    Suffix = proplists:get_value(file_suffix, Opts,
848				 ?DEFAULT_FILE_SUFFIX),
849    AppDefault = proplists:get_value(app_default, Opts, ?APP_DEFAULT),
850    Includes = proplists:append_values(includes, Opts),
851
852    {A, M} = get_doc_links(App, Modules, Opts),
853    #env{file_suffix = Suffix,
854	 apps = A,
855	 modules = M,
856	 app_default = AppDefault,
857	 includes = Includes}.
858
859%% ---------------------------------------------------------------------
860%% Plug-in modules
861
862%% @doc See {@link edoc:run/2} for a description of the `doclet' option.
863
864%% NEW-OPTIONS: doclet
865%% DEFER-OPTIONS: edoc:run/2
866
867%% @private
868run_doclet(Fun, Opts) ->
869    run_plugin(doclet, ?DEFAULT_DOCLET, Fun, Opts).
870
871%% @doc See {@link edoc:layout/2} for a description of the `layout'
872%% option.
873
874%% NEW-OPTIONS: layout
875%% DEFER-OPTIONS: edoc:layout/2
876
877%% @private
878run_layout(Fun, Opts) ->
879    run_plugin(layout, ?DEFAULT_LAYOUT, Fun, Opts).
880
881run_plugin(Name, Default, Fun, Opts) ->
882    run_plugin(Name, Name, Default, Fun, Opts).
883
884run_plugin(Name, Key, Default, Fun, Opts) when is_atom(Name) ->
885    Module = get_plugin(Key, Default, Opts),
886    case catch {ok, Fun(Module)} of
887	{ok, Value} ->
888	    Value;
889	R ->
890	    report("error in ~ts '~w': ~tP.", [Name, Module, R, 20]),
891	    exit(error)
892    end.
893
894get_plugin(Key, Default, Opts) ->
895    case proplists:get_value(Key, Opts, Default) of
896	M when is_atom(M) ->
897	    M;
898	Other ->
899	    report("bad value for option '~w': ~tP.", [Key, Other, 10]),
900	    exit(error)
901    end.
902
903
904%% ---------------------------------------------------------------------
905%% Error handling
906
907-type line() :: erl_anno:line().
908-type err()  :: 'eof'
909	      | {'missing', char()}
910	      | {line(), atom(), string()}
911	      | string().
912
913-spec throw_error(err(), line()) -> no_return().
914
915throw_error({missing, C}, L) ->
916    throw_error({"missing '~c'.", [C]}, L);
917throw_error(eof, L) ->
918    throw({error,L,"unexpected end of expression."});
919throw_error({L, M, D}, _L) ->
920    throw({error,L,{format_error,M,D}});
921throw_error(D, L) ->
922    throw({error, L, D}).
923