1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21
22-module(ic_file).
23
24-include_lib("ic/src/ic.hrl").
25
26%%-----------------------------------------------------------------
27%% External exports
28%%-----------------------------------------------------------------
29-export([filename_push/4, filename_pop/2, open/2, close/1, remove_ext/1, join/2,
30	 add_dot_erl/1, add_dot_hrl/1, add_dot_c/1, add_dot_h/1, add_dot_java/1,
31	 add_dot_idl/1, javaInterfaceFilePush/3, javaInterfaceFilePop/1,
32	 createDirectory/2, createJavaDirectory/2, open_java_file/3]).
33
34%%-----------------------------------------------------------------
35%% Internal exports
36%%-----------------------------------------------------------------
37-export([]).
38
39%%-----------------------------------------------------------------
40%% External functions
41%%-----------------------------------------------------------------
42
43%%-----------------------------------------------------------------
44%% Func: filename_push
45%%
46%% Pushes a file name, can also push ignore in which case means that
47%% no files should ever be opened at this scope. Note that empty in
48%% the file descriptor entries means that the file just isn't open
49%% yet.
50%%-----------------------------------------------------------------
51filename_push(G, _N, ignore, _) ->
52    G#genobj{stubfile=[ignore | G#genobj.stubfile],
53	     stubfiled=[ignore | G#genobj.stubfiled],
54	     skelfile=[ignore | G#genobj.skelfile],
55	     skelfiled=[ignore | G#genobj.skelfiled],
56    	     includefile=[ignore | G#genobj.includefile],
57	     includefiled=[ignore | G#genobj.includefiled]};
58
59filename_push(G, N, X, Lang) ->
60    Fullname = [ic_forms:get_id2(X) | N],
61    EName0 = ic_util:to_undersc(Fullname),
62
63    DoGen = ic_genobj:do_gen(G),
64
65    ImplName = find_impl_name(G, Fullname),
66
67    {StubName, EName} =
68	case Lang of
69	    erlang ->
70		{join(ic_options:get_opt(G, stubdir), add_dot_erl(EName0)),
71		 EName0};
72	    erlang_template ->
73		{join(ic_options:get_opt(G, stubdir), add_dot_erl(ImplName)),
74		 ImplName};
75	    c ->
76		{join(ic_options:get_opt(G, stubdir), add_dot_c(EName0)),
77		 EName0};
78	    c_server ->
79		{join(ic_options:get_opt(G, stubdir), add_dot_c(EName0++"__s")),
80		 EName0};
81	    erlang_template_no_gen ->
82		{undefined, EName0};
83	    erlang_no_stub ->
84		{undefined, EName0};
85	    c_no_stub ->
86		{undefined, EName0};
87	    c_server_no_stub ->
88		{undefined, EName0}
89	end,
90    Stub = if DoGen==true ->
91		   case StubName of
92		       undefined ->
93			   ignore;
94		       _ ->
95			   ic_codegen:emit_stub_head(G, open(empty, StubName), EName, Lang)
96		   end;
97	      true -> ignore end,
98
99    HrlName = case Lang of
100		  erlang_template ->
101		      ignore;
102		  erlang_template_no_gen ->
103		      ignore;
104		  erlang ->
105		      ?ifopt2(G, gen_hrl,
106			      join(ic_options:get_opt(G, stubdir), add_dot_hrl(EName)),
107			      ignore);
108		  c ->
109		      ?ifopt2(G, gen_hrl,
110			      join(ic_options:get_opt(G, stubdir), add_dot_h(EName)),
111			      ignore);
112		  c_server ->
113		      ?ifopt2(G, gen_hrl,
114			      join(ic_options:get_opt(G, stubdir),
115				   add_dot_h(EName++"__s")),
116			      ignore);
117		  erlang_no_stub ->
118		      ?ifopt2(G, gen_hrl,
119			      join(ic_options:get_opt(G, stubdir), add_dot_hrl(EName)),
120			      ignore);
121		  c_no_stub ->
122		      ?ifopt2(G, gen_hrl,
123			      join(ic_options:get_opt(G, stubdir), add_dot_h(EName)),
124			      ignore);
125		  c_server_no_stub ->
126		      ?ifopt2(G, gen_hrl,
127			      join(ic_options:get_opt(G, stubdir),
128				   add_dot_h(EName++"__s")),
129			      ignore)
130	      end,
131    Hrl = if  DoGen==true ->
132		  case Lang of
133		      erlang_template ->
134			  ignore;
135		      erlang_template_no_gen ->
136			  ignore;
137		      erlang_no_stub ->
138			  ic_codegen:emit_hrl_head(G, open(empty, HrlName),
139						   EName, erlang);
140		      c_no_stub ->
141			  ic_codegen:emit_hrl_head(G, open(empty, HrlName),
142						   EName, c);
143		      c_server_no_stub ->
144			  ic_codegen:emit_hrl_head(G, open(empty, HrlName),
145						   EName, c_server);
146		      _ ->
147			  ic_codegen:emit_hrl_head(G, open(empty, HrlName),
148						   EName, Lang)
149		  end;
150	      true -> ignore end,
151
152    G#genobj{impl=ImplName,
153	     stubfile=[StubName | G#genobj.stubfile],
154	     stubfiled=[Stub | G#genobj.stubfiled],
155	     includefile=[HrlName | G#genobj.includefile],
156	     includefiled=[Hrl | G#genobj.includefiled]}.
157
158%%-----------------------------------------------------------------
159%% Func: join/2
160%%
161%% Special version of filename join.
162%%-----------------------------------------------------------------
163join([], File) ->
164    File;
165join(Path, File) ->
166    filename:join(Path, File).
167
168
169%%-----------------------------------------------------------------
170%% Func: filename_pop/2
171%%-----------------------------------------------------------------
172filename_pop(G, Lang) ->
173%%    io:format("Popped file names: ~p~n", [hd(G#genobj.stubfile)]),
174%%    case is_skelfile_open(G) of
175%%	true -> emit_skel_footer(G);
176%%	false -> ok end,
177%%    close(hd(G#genobj.skelfiled)),
178    close(hd(G#genobj.stubfiled)),
179    ic_codegen:emit_hrl_foot(G, Lang),
180    close(hd(G#genobj.includefiled)),
181    G#genobj{stubfile=tl(G#genobj.stubfile),
182	     stubfiled=tl(G#genobj.stubfiled),
183%%	     skelfile=tl(G#genobj.skelfile),
184%%	     skelfiled=tl(G#genobj.skelfiled),
185    	     includefile=tl(G#genobj.includefile),
186	     includefiled=tl(G#genobj.includefiled)}.
187
188
189
190%%-----------------------------------------------------------------
191%% Func: javaInterfaceFilePush/3
192%%-----------------------------------------------------------------
193javaInterfaceFilePush(G, N, X) ->
194    Name = ic_forms:get_java_id(X),
195    {InterfaceFd, InterfaceFileName} = open_java_file(G, N, Name),
196
197    StubClassName = "_" ++ Name ++ "Stub",
198    {StubFd, StubFileName} = open_java_file(G, N, StubClassName),
199
200    SkelClassName = "_" ++ Name ++ "ImplBase",
201    {SkelFd, SkelFileName} = open_java_file(G, N, SkelClassName),
202
203    HelperClassName = Name ++ "Helper",
204    {HelperFd, HelperFileName} = open_java_file(G, N, HelperClassName),
205
206    HolderClassName = Name ++ "Holder",
207    {HolderFd, HolderFileName} = open_java_file(G, N, HolderClassName),
208
209    G#genobj{
210      interfacefile=[InterfaceFileName | G#genobj.interfacefile],
211      interfacefiled=[InterfaceFd | G#genobj.interfacefiled],
212      stubfile=[StubFileName | G#genobj.stubfile],
213      stubfiled=[StubFd | G#genobj.stubfiled],
214      skelfile=[SkelFileName | G#genobj.skelfile],
215      skelfiled=[SkelFd | G#genobj.skelfiled],
216      helperfile=[HelperFileName | G#genobj.helperfile],
217      helperfiled=[HelperFd | G#genobj.helperfiled],
218      holderfile=[HolderFileName | G#genobj.holderfile],
219      holderfiled=[HolderFd | G#genobj.holderfiled]}.
220
221
222
223
224
225%%-----------------------------------------------------------------
226%% Func: javaInterfaceFilePop/1
227%%-----------------------------------------------------------------
228javaInterfaceFilePop(G) ->
229    close(hd(G#genobj.interfacefiled)),
230    close(hd(G#genobj.stubfiled)),
231    close(hd(G#genobj.skelfiled)),
232    close(hd(G#genobj.helperfiled)),
233    close(hd(G#genobj.holderfiled)),
234    G#genobj{
235      interfacefile=tl(G#genobj.interfacefile),
236      interfacefiled=tl(G#genobj.interfacefiled),
237      stubfile=tl(G#genobj.stubfile),
238      stubfiled=tl(G#genobj.stubfiled),
239      skelfile=tl(G#genobj.skelfile),
240      skelfiled=tl(G#genobj.skelfiled),
241      helperfile=tl(G#genobj.helperfile),
242      helperfiled=tl(G#genobj.helperfiled),
243      holderfile=tl(G#genobj.holderfile),
244      holderfiled=tl(G#genobj.holderfiled)}.
245
246%%-----------------------------------------------------------------
247%% Func: createDirectory/2
248%%-----------------------------------------------------------------
249createDirectory(_G, []) ->
250    ok;
251createDirectory(G, Scope) ->
252    Path = ic_file:join(ic_options:get_opt(G, stubdir), ic_pragma:slashify(Scope)),
253    case file:make_dir(Path) of
254	ok ->
255	    ok;
256	{error, eexist} ->
257	    ok;
258	{error, Reason} ->
259	    ic_error:fatal_error(G, {create_dir, Path, Reason})
260    end.
261
262
263%%-----------------------------------------------------------------
264%% Func: createJavaDirectory/2
265%%-----------------------------------------------------------------
266createJavaDirectory(_G, []) ->
267    ok;
268createJavaDirectory(G, Scope) ->
269    JavaScope = ic_util:adjustScopeToJava(G,Scope),
270    Path = ic_file:join(ic_options:get_opt(G, stubdir), ic_pragma:slashify(JavaScope)),
271    case file:make_dir(Path) of
272	ok ->
273	    ok;
274	{error, eexist} ->
275	    ok;
276	{error, Reason} ->
277	    ic_error:fatal_error(G, {create_dir, Path, Reason})
278    end.
279
280
281
282
283%%-----------------------------------------------------------------
284%% Func: createJavaFileName/3
285%%-----------------------------------------------------------------
286createJavaFileName(G, Scope, FName) ->
287    JavaScope = ic_util:adjustScopeToJava(G,Scope),
288    join(ic_options:get_opt(G, stubdir),
289	 ic_pragma:slashify([FName++".java"|JavaScope])).
290
291%%-----------------------------------------------------------------
292%% Func: close/2 (used to be file_close)
293%%-----------------------------------------------------------------
294close(empty) -> ok;
295close(ignore) -> ok;
296close(Fd) ->
297    file:close(Fd).
298
299%%-----------------------------------------------------------------
300%% Func: remove_ext/1
301%%-----------------------------------------------------------------
302remove_ext(File) ->
303    filename:rootname(filename:basename(File)).
304
305%%-----------------------------------------------------------------
306%% Func: open/2 (used to be file_open)
307%%-----------------------------------------------------------------
308open(_, ignore) -> ignore;
309open(empty, Name) ->
310    case file:open(Name, [raw, binary, write]) of
311	{ok, Fd} ->
312	    Fd;
313	{error, Reason} ->
314	    exit({error, Reason})
315%%		ic_error:fatal_error(G, {open_file, Name, Reason})
316    end.
317
318%%-----------------------------------------------------------------
319%% Func: open_java_file/3
320%%-----------------------------------------------------------------
321open_java_file(G, N, Name) ->
322    createJavaDirectory(G, N),
323    FName =  createJavaFileName(G, N, Name),
324    case file:open(FName, [raw, binary, write]) of
325        {ok, Fd} ->
326	    ic_codegen:emit_stub_head(G, Fd, Name, java),
327	    emit_package(G, N, Fd),
328            {Fd, FName};
329        {error, Reason} ->
330	    ic_error:fatal_error(G, {open_file, FName, Reason})
331    end.
332
333%%-----------------------------------------------------------------
334%% Func: emit_package/3
335%%-----------------------------------------------------------------
336emit_package(_G, [], _Fd) ->
337    ok;
338emit_package(G, N, Fd) ->
339    ic_codegen:emit(Fd, "package ~s;\n", [ic_util:to_dot(G,N)]),
340    ic_codegen:nl(Fd).
341
342%%-----------------------------------------------------------------
343%% Func: add_dot_erl/1
344%%-----------------------------------------------------------------
345add_dot_erl(F) ->
346    File = ic_util:to_list(F),
347    F2 = lists:reverse(File),
348    case F2 of
349	[$l, $r, $e, $. | _Rest] ->
350	    File;
351	_ ->
352	    File ++ ".erl"
353    end.
354
355%%-----------------------------------------------------------------
356%% Func: add_dot_hrl/1
357%%-----------------------------------------------------------------
358add_dot_hrl(F) ->
359    File = ic_util:to_list(F),
360    F2 = lists:reverse(File),
361    case F2 of
362	[$l, $r, $h, $. | _Rest] ->
363	    File;
364	_ ->
365	    File ++ ".hrl"
366    end.
367
368%%-----------------------------------------------------------------
369%% Func: add_dot_c/1
370%%-----------------------------------------------------------------
371add_dot_c(F) ->
372    File = ic_util:to_list(F),
373    F2 = lists:reverse(File),
374    case F2 of
375	[$c, $. | _Rest] ->
376	    File;
377	_ ->
378	    File ++ ".c"
379    end.
380
381%%-----------------------------------------------------------------
382%% Func: add_dot_h/1
383%%-----------------------------------------------------------------
384add_dot_h(F) ->
385    File = ic_util:to_list(F),
386    F2 = lists:reverse(File),
387    case F2 of
388	[$h, $. | _Rest] ->
389	    File;
390	_ ->
391	    File ++ ".h"
392    end.
393
394%%-----------------------------------------------------------------
395%% Func: add_dot_java/1
396%%-----------------------------------------------------------------
397add_dot_java(F) ->
398    File = ic_util:to_list(F),
399    F2 = lists:reverse(File),
400    case F2 of
401	[$a, $v, $a, $j, $. | _Rest] ->
402	    File;
403	_ ->
404	    File ++ ".java"
405    end.
406
407%%-----------------------------------------------------------------
408%% Func: add_dot_idl/1
409%%-----------------------------------------------------------------
410add_dot_idl(F) ->
411    File = ic_util:to_list(F),
412    F2 = lists:reverse(File),
413    case F2 of
414	[$l, $d, $i, $. | _Rest] ->
415	    File;
416	_ ->
417	    File ++ ".idl"
418    end.
419
420
421%%-----------------------------------------------------------------
422%% Internal functions
423%%-----------------------------------------------------------------
424
425%%--------------------------------------------------------------------
426%%
427%% File handling stuff
428%%
429%%
430%%	Shall open a file for writing. Also sets up the generator with
431%%	usefull bits of information
432%%
433%%--------------------------------------------------------------------
434find_impl_name(G, Name) ->
435    N1 = ic_util:to_colon(Name),
436    N2 = ic_util:to_undersc(Name),
437    case {ic_options:get_opt(G, {impl, N1}),
438	  ic_options:get_opt(G, {impl, N2})} of
439	{false, false} ->
440	    case {ic_options:get_opt(G, {impl, "::"++N1}),
441		  ic_options:get_opt(G, {impl, N2})} of
442		{false, false} -> N2 ++ "_impl";
443		{X, _Y} when X /= false -> ic_util:to_list(X);
444		{_X, Y} when Y /= false -> ic_util:to_list(Y)
445	    end;
446	{X, _Y} when X /= false -> ic_util:to_list(X);
447	{_X, Y} when Y /= false -> ic_util:to_list(Y)
448    end.
449