1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2002-2008, 2011, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <common/arglex.h>
20 #include <common/nstring/list.h>
21 #include <common/trace.h>
22 #include <common/wstring/list.h>
23 #include <libaegis/change/file.h>
24 #include <libaegis/change.h>
25 #include <libaegis/cstate.fmtgen.h>
26 #include <libaegis/os.h>
27 #include <libaegis/project/file.h>
28 #include <libaegis/project.h>
29 #include <libaegis/sub/base_relativ.h>
30 #include <libaegis/sub.h>
31 
32 
33 //
34 // NAME
35 //      sub_base_relative - the source substitution
36 //
37 // SYNOPSIS
38 //      string_ty *sub_base_relative(wstring_list_ty *arg);
39 //
40 // DESCRIPTION
41 //      The sub_base_relative function implements the base_relative
42 //      substitution.  The base_relative substitution is replaced by the
43 //      path of the source file, relative to the base of the project tree.
44 //
45 //      Requires exactly one argument.
46 //
47 // ARGUMENTS
48 //      arg     - list of arguments, including the function name as [0]
49 //
50 // RETURNS
51 //      a pointer to a string in dynamic memory;
52 //      or NULL on error, setting suberr appropriately.
53 //
54 
55 wstring
sub_base_relative(sub_context_ty * scp,const wstring_list & arg)56 sub_base_relative(sub_context_ty *scp, const wstring_list &arg)
57 {
58     //
59     // Find the change.  If there is no change, it is also valid in
60     // the baseline context.
61     //
62     trace(("sub_base_relative()\n{\n"));
63     wstring result;
64     change::pointer cp = sub_context_change_get(scp);
65     if (!cp)
66     {
67         project *pp = sub_context_project_get(scp);
68         if (!pp)
69         {
70             scp->error_set(i18n("not valid in current context"));
71             trace(("}\n"));
72             return result;
73         }
74         cp = pp->change_get();
75     }
76 
77     //
78     // make sure we like the arguments.
79     //
80     if (arg.size() < 2)
81     {
82         scp->error_set(i18n("requires one argument"));
83         trace(("}\n"));
84         return result;
85     }
86 
87     //
88     // make sure we are in an appropriate state
89     //
90     cstate_ty *cstate_data = cp->cstate_get();
91     if (cstate_data->state == cstate_state_awaiting_development)
92     {
93         scp->error_set(i18n("not valid in current context"));
94         trace(("}\n"));
95         return result;
96     }
97 
98     //
99     // Get the search path.
100     //
101     string_list_ty search_path;
102     if (cstate_data->state == cstate_state_completed)
103         cp->pp->search_path_get(&search_path, false);
104     else
105         cp->search_path_get(&search_path, false);
106 
107     //
108     // Turn the file name into an absolute path.
109     //
110     nstring_list results;
111     for (size_t k = 1; k < arg.size(); ++k)
112     {
113         nstring fn = arg[k].to_nstring();
114         change_become(cp);
115         nstring s = os_pathname(fn, true);
116         change_become_undo(cp);
117         fn = s;
118 
119         //
120         // Hunt down the search list, to see if the file is in any of those
121         // directories.
122         //
123         for (size_t j = 0; j < search_path.nstrings; ++j)
124         {
125             s = os_below_dir(nstring(search_path.string[j]), fn);
126             if (!s.empty())
127             {
128                 fn = s;
129                 break;
130             }
131         }
132         results.push_back(fn);
133     }
134 
135     //
136     // build the result
137     //
138     nstring s = results.unsplit();
139     result = wstring(s);
140 
141     //
142     // here for all exits
143     //
144     trace(("return %p;\n", result.get_ref()));
145     trace(("}\n"));
146     return result;
147 }
148 
149 
150 // vim: set ts=8 sw=4 et :
151