source: rtems-tools/linkers/rld-process.cpp @ 2ce23a3

4.104.115
Last change on this file since 2ce23a3 was 2ce23a3, checked in by Chris Johns <chrisj@…>, on 08/01/14 at 06:47:11

Fix building on Windows with the latest MSVC.

Remove some warnings.

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "config.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#ifdef HAVE_SYS_WAIT_H
29#include <sys/wait.h>
30#endif
31
32#ifndef WIFEXITED
33#define WIFEXITED(S) (((S) & 0xff) == 0)
34#endif
35#ifndef WEXITSTATUS
36#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
37#endif
38#ifndef WIFSIGNALED
39#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
40#endif
41#ifndef WTERMSIG
42#define WTERMSIG(S) ((S) & 0x7f)
43#endif
44#ifndef WIFSTOPPED
45#define WIFSTOPPED WIFEXITED
46#endif
47#ifndef WSTOPSIG
48#define WSTOPSIG WEXITSTATUS
49#endif
50
51#include <iostream>
52
53#include "rld.h"
54#include "rld-process.h"
55
56#include <libiberty.h>
57
58namespace rld
59{
60  namespace process
61  {
62    temporary_files::temporary_files ()
63    {
64    }
65
66    temporary_files::~temporary_files ()
67    {
68      clean_up ();
69    }
70
71    const std::string
72    temporary_files::get ()
73    {
74      char* temp = ::make_temp_file ("rldXXXXXX");
75
76      if (!temp)
77        throw rld::error ("bad temp name", "pex");
78
79      std::string name = temp;
80
81      tempfiles.push_back (name);
82
83      return name;
84    }
85
86    void
87    temporary_files::unlink (const std::string& name)
88    {
89      struct stat sb;
90      if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
91      {
92        int r;
93#if _WIN32
94        r = ::remove(name.c_str ());
95#else
96        r = ::unlink (name.c_str ());
97#endif
98        if (r < 0)
99        {
100          std::cerr << "error: unlinking temp file: " << name << std::endl;
101          ::exit (100);
102        }
103      }
104    }
105
106    void
107    temporary_files::erase (const std::string& name)
108    {
109      for (tempfile_container::iterator tfi = tempfiles.begin ();
110           tfi != tempfiles.end ();
111           ++tfi)
112      {
113        if (*tfi == name)
114        {
115          unlink (name);
116          tempfiles.erase (tfi);
117          break;
118        }
119      }
120    }
121
122    void
123    temporary_files::clean_up ()
124    {
125      for (tempfile_container::iterator tfi = tempfiles.begin ();
126           tfi != tempfiles.end ();
127           ++tfi)
128      {
129        unlink (*tfi);
130      }
131    }
132
133    tempfile::tempfile ()
134      : fd (-1),
135        level (0)
136    {
137      _name = temporaries.get ();
138    }
139
140    tempfile::~tempfile ()
141    {
142      close ();
143      temporaries.erase (_name);
144    }
145
146    void
147    tempfile::open ()
148    {
149      if ((fd < 0) && rld::files::check_file (_name))
150      {
151        level = 0;
152        fd = ::open (_name.c_str (), O_RDONLY);
153        if (fd < 0)
154          throw rld::error (::strerror (errno), "tempfile open:" + _name);
155      }
156    }
157
158    void
159    tempfile::close ()
160    {
161      if (fd != -1)
162      {
163        ::close (fd);
164        fd = -1;
165        level = 0;
166      }
167    }
168
169    const std::string&
170    tempfile::name () const
171    {
172      return _name;
173    }
174
175    size_t
176    tempfile::size ()
177    {
178      if (fd < 0)
179        return 0;
180
181      struct stat sb;
182      if (::stat (_name.c_str (), &sb) == 0)
183        return sb.st_size;
184
185      return 0;
186    }
187
188    void
189    tempfile::get (std::string& all)
190    {
191      all.clear ();
192      if (fd != -1)
193      {
194        if (level)
195          all.append (buf, level);
196        level = 0;
197        while (true)
198        {
199          int read = ::read (fd, buf, sizeof (buf) );
200          if (read < 0)
201            throw rld::error (::strerror (errno), "tempfile get read:" + _name);
202          else if (read == 0)
203            break;
204          else
205            all.append (buf, read);
206        }
207      }
208    }
209
210    void
211    tempfile::getline (std::string& line)
212    {
213      line.clear ();
214      if (fd != -1)
215      {
216        if (level)
217          line.append (buf, level);
218        level = 0;
219        while (true)
220        {
221          int read = ::read (fd, buf, sizeof (buf));
222          if (read < 0)
223            throw rld::error (::strerror (errno), "tempfile read:" + _name);
224          else if (read == 0)
225            break;
226          else
227          {
228            char* lf = ::strchr (buf, '\n');
229            if (lf)
230            {
231              int len = lf - &buf[0] + 1;
232              line.append (buf, len);
233              level = read - len;
234              if (level)
235                ::memmove (buf, &buf[len], level);
236              break;
237            }
238            line.append (buf, read);
239          }
240        }
241      }
242    }
243
244    void
245    tempfile::output (std::ostream& out)
246    {
247      std::string prefix;
248      output (prefix, out);
249    }
250
251    void
252    tempfile::output (const std::string& prefix,
253                      std::ostream&      out,
254                      bool               line_numbers)
255    {
256      if (fd == -1)
257      {
258        std::string line;
259        int         lc = 0;
260        open ();
261        while (true)
262        {
263          getline (line);
264          ++lc;
265          if (line.empty ())
266            break;
267          if (!prefix.empty ())
268            out << prefix << ':';
269          if (line_numbers)
270            out << lc << ':';
271          out << line;
272        }
273        close ();
274      }
275    }
276
277    status
278    execute (const std::string& pname,
279             const std::string& command,
280             const std::string& outname,
281             const std::string& errname)
282    {
283      arg_container args;
284      parse_command_line (command, args);
285      return execute (pname, args, outname, errname);
286    }
287
288    status
289    execute (const std::string&   pname,
290             const arg_container& args,
291             const std::string&   outname,
292             const std::string&   errname)
293    {
294      if (rld::verbose () >= RLD_VERBOSE_TRACE)
295      {
296        std::cout << "execute: ";
297        for (size_t a = 0; a < args.size (); ++a)
298          std::cout << args[a] << ' ';
299        std::cout << std::endl;
300      }
301
302      const char** cargs = new const char* [args.size () + 1];
303
304      for (size_t a = 0; a < args.size (); ++a)
305        cargs[a] = args[a].c_str ();
306      cargs[args.size ()] = 0;
307
308      int err = 0;
309      int s = 0;
310
311      const char* serr = pex_one (PEX_LAST | PEX_SEARCH,
312                                  args[0].c_str (),
313                                  (char* const*) cargs,
314                                  pname.c_str (),
315                                  outname.c_str (),
316                                  errname.c_str (),
317                                  &s,
318                                  &err);
319
320      delete [] cargs;
321
322      if (serr)
323        throw rld::error ("execute: " + args[0], serr);
324      else if (err)
325        throw rld::error ("execute: " + args[0], ::strerror (err));
326
327      status _status;
328
329      if (rld::verbose () >= RLD_VERBOSE_TRACE)
330        std::cout << "execute: status: ";
331
332      if (WIFEXITED (s))
333      {
334        _status.type = status::normal;
335        _status.code = WEXITSTATUS (s);
336        if (rld::verbose () >= RLD_VERBOSE_TRACE)
337          std::cout << _status.code << std::endl;
338      }
339      else if (WIFSIGNALED (s))
340      {
341        _status.type = status::signal;
342        _status.code = WTERMSIG (s);
343        if (rld::verbose () >= RLD_VERBOSE_TRACE)
344          std::cout << "signal: " << _status.code << std::endl;
345      }
346      else if (WIFSTOPPED (s))
347      {
348        _status.type = status::stopped;
349        _status.code = WSTOPSIG (s);
350        if (rld::verbose () >= RLD_VERBOSE_TRACE)
351          std::cout << "stopped: " << _status.code << std::endl;
352      }
353      else
354        throw rld::error ("execute: " + args[0], "unknown status returned");
355
356      return _status;
357    }
358
359    /*
360     * The code is based on this C file:
361     *  http://cybertiggyr.com/pcm/src/parse.c
362     */
363    void
364    parse_command_line (const std::string& command, arg_container& args)
365    {
366      enum pstate
367      {
368        pstate_discard_space,
369        pstate_accumulate_quoted,
370        pstate_accumulate_raw
371      };
372
373      args.clear ();
374
375      const char quote = '"';
376      const char escape = '\\';
377      pstate     state = pstate_discard_space;
378      size_t     start = 0;
379      size_t     i = 0;
380
381      while (i < command.size ())
382      {
383        switch (state)
384        {
385          case pstate_discard_space:
386            if (command[i] == quote)
387            {
388              ++i;
389              start = i;
390              state = pstate_accumulate_quoted;
391            }
392            else if (::isspace (command[i]))
393            {
394              ++i;
395            }
396            else /* includes escape */
397            {
398              start = i;
399              state = pstate_accumulate_raw;
400            }
401            break;
402
403          case pstate_accumulate_quoted:
404            if (command[i] == quote)
405            {
406              args.push_back (command.substr (start, i - 1));
407              ++i;
408              state = pstate_discard_space;
409            }
410            else if ((command[i] == escape) && (command[i + 1] == quote))
411            {
412              i += 2;
413            }
414            else /* includes space */
415            {
416              ++i;
417            }
418            break;
419
420          case pstate_accumulate_raw:
421            if (command[i] == quote)
422            {
423              throw rld::error ("quote in token", "command parse");
424            }
425            else if ((command[i] == escape) && (command[i + 1] == quote))
426            {
427              i += 2;
428            }
429            else if (::isspace (command[i]))
430            {
431              args.push_back (command.substr (start, i - 1));
432              ++i;
433              state = pstate_discard_space;
434            }
435            else
436            {
437              ++i;
438            }
439            break;
440        }
441      }
442    }
443  }
444}
Note: See TracBrowser for help on using the repository browser.