GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
kpse.cc
Go to the documentation of this file.
1 // This file is not compiled to a separate object file.
2 // It is included in pathsearch.cc.
3 
4 /* Look up a filename in a path.
5 
6 Copyright (C) 2003-2017 John W. Eaton
7 Copyright (C) 1993, 94, 95, 96, 97, 98 Karl Berry.
8 Copyright (C) 1993, 94, 95, 96, 97 Karl Berry & O. Weber.
9 Copyright (C) 1992, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
10 
11 This file is part of Octave.
12 
13 Octave is free software; you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by the
15 Free Software Foundation; either version 3 of the License, or (at your
16 option) any later version.
17 
18 Octave is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with Octave; see the file COPYING. If not, see
25 <http://www.gnu.org/licenses/>.
26 
27 */
28 
29 #if defined (HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
32 
33 #include <cctype>
34 #include <cerrno>
35 #include <cstdlib>
36 
37 #include <map>
38 #include <fstream>
39 #include <iostream>
40 #include <string>
41 
42 #include "dir-ops.h"
43 #include "file-ops.h"
44 #include "file-stat.h"
45 #include "kpse.h"
46 #include "oct-env.h"
47 #include "oct-passwd.h"
48 #include "oct-time.h"
49 #include "pathsearch.h"
50 #include "unistd-wrappers.h"
51 
52 #if defined (OCTAVE_USE_WINDOWS_API)
53 # define WIN32_LEAN_AND_MEAN 1
54 # include <windows.h>
55 #endif
56 
57 // Define the characters which separate components of filenames and
58 // environment variable paths.
59 
60 #define IS_DEVICE_SEP(ch) octave::sys::file_ops::is_dev_sep (ch)
61 #define NAME_BEGINS_WITH_DEVICE(name) \
62  (name.length () > 0 && IS_DEVICE_SEP ((name)[1]))
63 
64 #define DIR_SEP_STRING octave::sys::file_ops::dir_sep_str ()
65 #define IS_DIR_SEP(ch) octave::sys::file_ops::is_dir_sep (ch)
66 
67 #define ENV_SEP octave::directory_path::path_sep_char ()
68 #define ENV_SEP_STRING octave::directory_path::path_sep_str ()
69 #define IS_ENV_SEP(ch) octave::directory_path::is_path_sep (ch)
70 
71 // If NO_DEBUG is defined (not recommended), skip all this.
72 #if ! defined (NO_DEBUG)
73 
74 // OK, we'll have tracing support.
75 # define KPSE_DEBUG
76 
77 // Test if a bit is on.
78 # define KPSE_DEBUG_P(bit) (kpse_debug & (1 << (bit)))
79 
80 # define KPSE_DEBUG_STAT 0 // stat calls
81 # define KPSE_DEBUG_EXPAND 1 // path element expansion
82 # define KPSE_DEBUG_SEARCH 2 // searches
83 # define KPSE_DEBUG_VARS 3 // variable values
84 # define KPSE_LAST_DEBUG KPSE_DEBUG_VARS
85 
86 #endif
87 
88 unsigned int kpse_debug = 0;
89 
90 static std::string kpse_var_expand (const std::string& src);
91 
92 static std::string kpse_expand (const std::string& s);
93 
94 void
96 {
97  e = b + 1;
98 
99  if (e == len)
100  ; // OK, we have found the last element.
101  else if (e > len)
102  b = e = std::string::npos;
103  else
104  {
105  // Find the next colon not enclosed by braces (or the end of the
106  // path).
107 
109  e++;
110  }
111 }
112 
113 void
115 {
116  b = e + 1;
117 
118  // Skip any consecutive colons.
120  b++;
121 
122  if (b >= len)
123  b = e = std::string::npos;
124  else
125  set_end ();
126 }
127 
128 /* Truncate any too-long components in NAME, returning the result. It's
129  too bad this is necessary. See comments in readable.c for why. */
130 
131 static std::string
133 {
134  unsigned c_len = 0; /* Length of current component. */
135  unsigned ret_len = 0; /* Length of constructed result. */
136 
137  std::string ret = name;
138 
139  size_t len = name.length ();
140 
141  for (size_t i = 0; i < len; i++)
142  {
143  if (IS_DIR_SEP (name[i]) || IS_DEVICE_SEP (name[i]))
144  {
145  /* At a directory delimiter, reset component length. */
146  c_len = 0;
147  }
148  else if (c_len > octave::sys::dir_entry::max_name_length ())
149  {
150  /* If past the max for a component, ignore this character. */
151  continue;
152  }
153 
154  /* Copy this character. */
155  ret[ret_len++] = name[i];
156  c_len++;
157  }
158 
159  ret.resize (ret_len);
160 
161  return ret;
162 }
163 
164 /* If access can read FN, run stat (assigning to stat buffer ST) and
165  check that fn is not a directory. Don't check for just being a
166  regular file, as it is potentially useful to read fifo's or some
167  kinds of devices. */
168 
169 #if defined (OCTAVE_USE_WINDOWS_API)
170 static inline bool
171 READABLE (const std::string& fn)
172 {
173  const char *t = fn.c_str ();
174  return (GetFileAttributes (t) != 0xFFFFFFFF
175  && ! (GetFileAttributes (t) & FILE_ATTRIBUTE_DIRECTORY));
176 }
177 #else
178 static inline bool
180 {
181  bool retval = false;
182 
183  const char *t = fn.c_str ();
184 
185  if (octave_access_wrapper (t, octave_access_r_ok ()) == 0)
186  {
188 
189  retval = fs && ! fs.is_dir ();
190  }
191 
192  return retval;
193 }
194 #endif
195 
196 /* POSIX invented the brain-damage of not necessarily truncating
197  filename components; the system's behavior is defined by the value of
198  the symbol _POSIX_NO_TRUNC, but you can't change it dynamically!
199 
200  Generic const return warning. See extend-fname.c. */
201 
202 static std::string
204 {
205  std::string ret;
206 
207  if (READABLE (name))
208  {
209  ret = name;
210 
211 #if defined (ENAMETOOLONG)
212  }
213  else if (errno == ENAMETOOLONG)
214  {
215  ret = kpse_truncate_filename (name);
216 
217  /* Perhaps some other error will occur with the truncated name,
218  so let's call access again. */
219 
220  if (! READABLE (ret))
221  {
222  /* Failed. */
223  ret = "";
224  }
225 #endif /* ENAMETOOLONG */
226 
227  }
228  else
229  {
230  /* Some other error. */
231  if (errno == EACCES)
232  {
233  /* Maybe warn them if permissions are bad. */
234  perror (name.c_str ());
235  }
236 
237  ret = "";
238  }
239 
240  return ret;
241 }
242 
243 static bool
244 kpse_absolute_p (const std::string& filename, int relative_ok)
245 {
246  return (octave::sys::env::absolute_pathname (filename)
247  || (relative_ok
249 }
250 
251 /* The very first search is for texmf.cnf, called when someone tries to
252  initialize the TFM path or whatever. init_path calls kpse_cnf_get
253  which calls kpse_all_path_search to find all the texmf.cnf's. We
254  need to do various special things in this case, since we obviously
255  don't yet have the configuration files when we're searching for the
256  configuration files. */
257 static bool first_search = true;
258 
259 /* This function is called after every search. */
260 
261 static void
262 log_search (const std::list<std::string>& filenames)
263 {
265  {
266  for (const auto &filename : filenames)
267  {
269  std::cerr << now.unix_time () << " " << filename << std::endl;
270  }
271  }
272 }
273 
274 /* Concatenate each element in DIRS with NAME (assume each ends with a
275  /, to save time). If SEARCH_ALL is false, return the first readable
276  regular file. Else continue to search for more. In any case, if
277  none, return a list containing just NULL.
278 
279  We keep a single buffer for the potential filenames and reallocate
280  only when necessary. I'm not sure it's noticeably faster, but it
281  does seem cleaner. (We do waste a bit of space in the return
282  value, though, since we don't shrink it to the final size returned.) */
283 
284 static std::list<std::string>
286  bool search_all)
287 {
288  std::list<std::string> ret;
289 
290  std::string potential = dir + name;
291 
292  std::string tmp = kpse_readable_file (potential);
293 
294  if (! tmp.empty ())
295  {
296  ret.push_back (potential);
297 
298  if (! search_all)
299  return ret;
300  }
301 
302  return ret;
303 }
304 
305 /* This is called when NAME is absolute or explicitly relative; if it's
306  readable, return (a list containing) it; otherwise, return NULL. */
307 
308 static std::list<std::string>
310 {
311  std::list<std::string> ret_list;
313 
314  /* Add 'found' to the return list even if it's null; that tells
315  the caller we didn't find anything. */
316  ret_list.push_back (found);
317 
318  return ret_list;
319 }
320 
321 /* This is the hard case -- look for NAME in PATH. If ALL is false,
322  return the first file found. Otherwise, search all elements of PATH. */
323 
324 static std::list<std::string>
325 path_search (const std::string& path, const std::string& name, bool all)
326 {
327  std::list<std::string> ret_list;
328  bool done = false;
329 
330  for (kpse_path_iterator pi (path); ! done && pi != std::string::npos; pi++)
331  {
332  std::string elt = *pi;
333 
334  std::list<std::string> found;
335 
336  /* Do not touch the device if present */
337  if (NAME_BEGINS_WITH_DEVICE (elt))
338  {
339  while (elt.length () > 3
340  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
341  {
342  elt[2] = elt[1];
343  elt[1] = elt[0];
344  elt = elt.substr (1);
345  }
346  }
347  else
348  {
349  /* We never want to search the whole disk. */
350  while (elt.length () > 1
351  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
352  elt = elt.substr (1);
353  }
354 
355  /* Our caller (search), also tests first_search, and does
356  the resetting. */
357  if (first_search)
358  found = std::list<std::string> ();
359 
360  /* Search the filesystem. */
361 
362  if (found.empty ())
363  {
364  std::string dir = kpse_element_dir (elt);
365 
366  if (! dir.empty ())
367  found = dir_search (dir, name, all);
368  }
369 
370  /* Did we find anything anywhere? */
371  if (! found.empty ())
372  {
373  if (all)
374  ret_list.splice (ret_list.end (), found);
375  else
376  {
377  ret_list.push_back (found.front ());
378  done = true;
379  }
380  }
381  }
382 
383  return ret_list;
384 }
385 
386 /* Search PATH for ORIGINAL_NAME. If ALL is false, or ORIGINAL_NAME is
387  absolute_p, check ORIGINAL_NAME itself. Otherwise, look at each
388  element of PATH for the first readable ORIGINAL_NAME.
389 
390  Always return a list; if no files are found, the list will
391  contain just NULL. If ALL is true, the list will be
392  terminated with NULL. */
393 
394 static std::list<std::string>
395 search (const std::string& path, const std::string& original_name,
396  bool all)
397 {
398  std::list<std::string> ret_list;
399  bool absolute_p;
400 
401  /* Make a leading ~ count as an absolute filename, and expand $FOO's. */
402  std::string name = kpse_expand (original_name);
403 
404  /* If the first name is absolute or explicitly relative, no need to
405  consider PATH at all. */
406  absolute_p = kpse_absolute_p (name, true);
407 
409  std::cerr << "kdebug: start search (file=" << name
410  << ", find_all=" << all << ", path=" << path << ")."
411  << std::endl;
412 
413  /* Find the file(s). */
414  ret_list = (absolute_p
415  ? absolute_search (name)
416  : path_search (path, name, all));
417 
418  /* The very first search is for texmf.cnf. We can't log that, since
419  we want to allow setting TEXMFLOG in texmf.cnf. */
420  if (first_search)
421  {
422  first_search = false;
423  }
424  else
425  {
426  /* Record the filenames we found, if desired. And wrap them in a
427  debugging line if we're doing that. */
428 
430  std::cerr << "kdebug: search (" << original_name << ") =>";
431 
432  log_search (ret_list);
433 
435  std::cerr << std::endl;
436  }
437 
438  return ret_list;
439 }
440 
441 /* Search PATH for the first NAME. */
442 
443 /* Call 'kpse_expand' on NAME. If the result is an absolute or
444  explicitly relative filename, check whether it is a readable
445  (regular) file.
446 
447  Otherwise, look in each of the directories specified in PATH (also do
448  tilde and variable expansion on elements in PATH).
449 
450  The caller must expand PATH. This is because it makes more sense to
451  do this once, in advance, instead of for every search using it.
452 
453  In any case, return the complete filename if found, otherwise NULL. */
454 
457 {
458  std::list<std::string> ret_list = search (path, name, false);
459 
460  return ret_list.empty () ? "" : ret_list.front ();
461 }
462 
463 /* Like 'kpse_path_search' with MUST_EXIST true, but return a list of
464  all the filenames (or NULL if none), instead of taking the first. */
465 
466 std::list<std::string>
468 {
469  return search (path, name, true);
470 }
471 
472 /* This is the hard case -- look in each element of PATH for each
473  element of NAMES. If ALL is false, return the first file found.
474  Otherwise, search all elements of PATH. */
475 
476 std::list<std::string>
478  const std::list<std::string>& names, bool all)
479 {
480  std::list<std::string> ret_list;
481  bool done = false;
482 
483  for (kpse_path_iterator pi (path); ! done && pi != std::string::npos; pi++)
484  {
485  std::string elt = *pi;
486 
487  std::string dir;
488  std::list<std::string> found;
489 
490  /* Do not touch the device if present */
491 
492  if (NAME_BEGINS_WITH_DEVICE (elt))
493  {
494  while (elt.length () > 3
495  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
496  {
497  elt[2] = elt[1];
498  elt[1] = elt[0];
499  elt = elt.substr (1);
500  }
501  }
502  else
503  {
504  /* We never want to search the whole disk. */
505  while (elt.length () > 1
506  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
507  elt = elt.substr (1);
508  }
509 
510  /* We have to search one directory at a time. */
511  dir = kpse_element_dir (elt);
512 
513  if (! dir.empty ())
514  {
515  for (auto it = names.cbegin (); it != names.cend () && ! done; it++)
516  {
517  std::string name = *it;
518 
519  /* Our caller (find_first_of), also tests first_search,
520  and does the resetting. */
521  if (first_search)
522  found = std::list<std::string> ();
523 
524  /* Search the filesystem. */
525 
526  if (found.empty ())
527  found = dir_search (dir, name, all);
528 
529  /* Did we find anything anywhere? */
530  if (! found.empty ())
531  {
532  if (all)
533  ret_list.splice (ret_list.end (), found);
534  else
535  {
536  ret_list.push_back (found.front ());
537  done = true;
538  }
539  }
540  }
541  }
542  }
543 
544  return ret_list;
545 }
546 
547 static std::list<std::string>
548 find_first_of (const std::string& path, const std::list<std::string>& names,
549  bool all)
550 {
551  std::list<std::string> ret_list;
552 
554  {
555  std::cerr << "kdebug: start find_first_of (";
556 
557  for (auto p = names.cbegin (); p != names.cend (); p++)
558  {
559  if (p == names.cbegin ())
560  std::cerr << *p;
561  else
562  std::cerr << ", " << *p;
563  }
564 
565  std::cerr << "), path=" << path << "." << std::endl;
566  }
567 
568  for (const auto &name : names)
569  {
570  if (kpse_absolute_p (name, true))
571  {
572  /* If the name is absolute or explicitly relative, no need
573  to consider PATH at all. If we find something, then we
574  are done. */
575 
576  ret_list = absolute_search (name);
577 
578  if (! ret_list.empty ())
579  return ret_list;
580  }
581  }
582 
583  /* Find the file. */
584  ret_list = path_find_first_of (path, names, all);
585 
586  /* The very first search is for texmf.cnf. We can't log that, since
587  we want to allow setting TEXMFLOG in texmf.cnf. */
588  if (first_search)
589  {
590  first_search = false;
591  }
592  else
593  {
594  /* Record the filenames we found, if desired. And wrap them in a
595  debugging line if we're doing that. */
596 
598  {
599  std::cerr << "kdebug: find_first_of (";
600 
601  for (auto p = names.cbegin (); p != names.cend (); p++)
602  {
603  if (p == names.cbegin ())
604  std:: cerr << *p;
605  else
606  std::cerr << ", " << *p;
607  }
608 
609  std::cerr << ") =>";
610  }
611 
612  log_search (ret_list);
613 
615  std::cerr << std::endl;
616  }
617 
618  return ret_list;
619 }
620 
621 /* Search each element of PATH for each element of NAMES. Return the
622  first one found. */
623 
624 /* Search each element of PATH for each element in the list of NAMES.
625  Return the first one found. */
626 
629  const std::list<std::string>& names)
630 {
631  std::list<std::string> ret_list = find_first_of (path, names, false);
632 
633  return ret_list.empty () ? "" : ret_list.front ();
634 }
635 
636 /* Search each element of PATH for each element of NAMES and return a
637  list containing everything found, in the order found. */
638 
639 /* Like 'kpse_path_find_first_of' with MUST_EXIST true, but return a
640  list of all the filenames (or NULL if none), instead of taking the
641  first. */
642 
643 std::list<std::string>
645  const std::list<std::string>& names)
646 {
647  return find_first_of (path, names, true);
648 }
649 
650 /* If NAME has a leading ~ or ~user, Unix-style, expand it to the user's
651  home directory, and return a new malloced string. If no ~, or no
652  <pwd.h>, just return NAME. */
653 
654 static std::string
656 {
657  std::string expansion;
658 
659  /* If no leading tilde, do nothing. */
660  if (name.empty () || name[0] != '~')
661  {
662  expansion = name;
663 
664  /* If a bare tilde, return the home directory or '.'. (Very
665  unlikely that the directory name will do anyone any good, but
666  ... */
667  }
668  else if (name.length () == 1)
669  {
671 
672  if (expansion.empty ())
673  expansion = ".";
674 
675  /* If '~/', remove any trailing / or replace leading // in $HOME.
676  Should really check for doubled intermediate slashes, too. */
677  }
678  else if (IS_DIR_SEP (name[1]))
679  {
680  unsigned c = 1;
682 
683  if (home.empty ())
684  home = ".";
685 
686  size_t home_len = home.length ();
687 
688  /* handle leading // */
689  if (home_len > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
690  home = home.substr (1);
691 
692  /* omit / after ~ */
693  if (IS_DIR_SEP (home[home_len - 1]))
694  c++;
695 
696  expansion = home + name.substr (c);
697 
698  /* If '~user' or '~user/', look up user in the passwd database (but
699  OS/2 doesn't have this concept. */
700  }
701  else
702 #if defined (HAVE_PWD_H)
703  {
704  unsigned c = 2;
705 
706  /* find user name */
707  while (name.length () > c && ! IS_DIR_SEP (name[c]))
708  c++;
709 
710  std::string user = name.substr (1, c-1);
711 
712  /* We only need the cast here for (deficient) systems
713  which do not declare 'getpwnam' in <pwd.h>. */
715 
716  /* If no such user, just use '.'. */
717  std::string home = p ? p.dir () : std::string (".");
718 
719  if (home.empty ())
720  home = ".";
721 
722  /* handle leading // */
723  if (home.length () > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
724  home = home.substr (1);
725 
726  /* If HOME ends in /, omit the / after ~user. */
727  if (name.length () > c && IS_DIR_SEP (home[home.length () - 1]))
728  c++;
729 
730  expansion = name.length () > c ? home : home + name.substr (c);
731  }
732 #else /* not HAVE_PWD_H */
733  expansion = name;
734 #endif /* not HAVE_PWD_H */
735 
736  return expansion;
737 }
738 
739 /* Do variable expansion first so ~${USER} works. (Besides, it's what the
740  shells do.) */
741 
742 /* Call kpse_var_expand and kpse_tilde_expand (in that order). Result
743  is always in fresh memory, even if no expansions were done. */
744 
745 static std::string
747 {
748  std::string var_expansion = kpse_var_expand (s);
749  return kpse_tilde_expand (var_expansion);
750 }
751 
752 /* Forward declarations of functions from the original expand.c */
753 static std::list<std::string> brace_expand (const std::string&);
754 
755 /* If $KPSE_DOT is defined in the environment, prepend it to any relative
756  path components. */
757 
758 static std::string
760 {
761  std::string ret;
762  std::string kpse_dot = octave::sys::env::getenv ("KPSE_DOT");
763 
764  if (kpse_dot.empty ())
765  return path;
766 
767  for (kpse_path_iterator pi (path); pi != std::string::npos; pi++)
768  {
769  std::string elt = *pi;
770 
771  /* Single "." get special treatment, as does "./" or its equivalent. */
772 
773  size_t elt_len = elt.length ();
774 
775  if (kpse_absolute_p (elt, false))
776  ret += elt + ENV_SEP_STRING;
777  else if (elt_len == 1 && elt[0] == '.')
778  ret += kpse_dot + ENV_SEP_STRING;
779  else if (elt_len > 1 && elt[0] == '.' && IS_DIR_SEP (elt[1]))
780  ret += kpse_dot + elt.substr (1) + ENV_SEP_STRING;
781  else
782  ret += kpse_dot + DIR_SEP_STRING + elt + ENV_SEP_STRING;
783  }
784 
785  int len = ret.length ();
786  if (len > 0)
787  ret.resize (len-1);
788 
789  return ret;
790 }
791 
792 /* Do brace expansion on ELT; then do variable and ~ expansion on each
793  element of the result; then do brace expansion again, in case a
794  variable definition contained braces (e.g., $TEXMF). Return a
795  string comprising all of the results separated by ENV_SEP_STRING. */
796 
797 static std::string
799 {
800  std::string ret;
801 
802  std::list<std::string> expansions = brace_expand (elt);
803 
804  for (const auto &expanded_elt : expansions)
805  {
806  /* Do $ and ~ expansion on each element. */
807  std::string x = kpse_expand (expanded_elt);
808 
809  if (x != elt)
810  {
811  /* If we did any expansions, do brace expansion again. Since
812  recursive variable definitions are not allowed, this recursion
813  must terminate. (In practice, it's unlikely there will ever be
814  more than one level of recursion.) */
816  }
817 
818  ret += x + ENV_SEP_STRING;
819  }
820 
821  ret.resize (ret.length () - 1);
822 
823  return ret;
824 }
825 
826 /* Do brace expansion and call 'kpse_expand' on each element of the
827  result; return the final expansion (always in fresh memory, even if
828  no expansions were done). */
829 
830 static std::string
832 {
833  /* Must do variable expansion first because if we have
834  foo = .:~
835  TEXINPUTS = $foo
836  we want to end up with TEXINPUTS = .:/home/karl.
837  Since kpse_path_element is not reentrant, we must get all
838  the path elements before we start the loop. */
840 
841  std::string ret;
842 
843  for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
844  {
845  std::string elt = *pi;
846 
847  /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}. */
848  std::string expansion = kpse_brace_expand_element (elt);
849  ret += expansion + ENV_SEP_STRING;
850  }
851 
852  size_t len = ret.length ();
853  if (len > 0)
854  ret.resize (len-1);
855 
856  return kpse_expand_kpse_dot (ret);
857 }
858 
859 /* Expand all special constructs in a path, and include only the actually
860  existing directories in the result. */
861 
862 /* Do brace expansion and call 'kpse_expand' on each argument of the
863  result. The final expansion (always in fresh memory) is a path of
864  all the existing directories that match the pattern. */
865 
868 {
869  std::string ret;
870  unsigned len;
871 
872  len = 0;
873 
874  /* Expand variables and braces first. */
876 
877  /* Now expand each of the path elements, printing the results */
878  for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
879  {
880  std::string elt = *pi;
881 
882  std::string dir;
883 
884  /* Do not touch the device if present */
885  if (NAME_BEGINS_WITH_DEVICE (elt))
886  {
887  while (elt.length () > 3
888  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
889  {
890  elt[2] = elt[1];
891  elt[1] = elt[0];
892  elt = elt.substr (1);
893  }
894  }
895  else
896  {
897  /* We never want to search the whole disk. */
898  while (elt.length () > 1
899  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
900  elt = elt.substr (1);
901  }
902 
903  /* Search the disk for all dirs in the component specified.
904  Be faster to check the database, but this is more reliable. */
905  dir = kpse_element_dir (elt);
906 
907  size_t dirlen = dir.length ();
908 
909  if (dirlen > 0)
910  {
911  ret += dir;
912  len += dirlen;
913 
914  /* Retain trailing slash if that's the root directory. */
915  if (dirlen == 1
916  || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (dir)
917  && IS_DIR_SEP (dir[2])))
918  {
919  ret += ENV_SEP_STRING;
920  len++;
921  }
922 
923  ret[len-1] = ENV_SEP;
924  }
925  }
926 
927  if (len > 0)
928  ret.resize (len-1);
929 
930  return ret;
931 }
932 
933 /* braces.c -- code for doing word expansion in curly braces. Taken from
934  bash 1.14.5. [And subsequently modified for kpatshea.]
935 
936  Copyright (C) 1987,1991 Free Software Foundation, Inc. */
937 
938 #define brace_whitespace(c) (! (c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
939 
940 /* Basic idea:
941 
942  Segregate the text into 3 sections: preamble (stuff before an open brace),
943  postamble (stuff after the matching close brace) and amble (stuff after
944  preamble, and before postamble). Expand amble, and then tack on the
945  expansions to preamble. Expand postamble, and tack on the expansions to
946  the result so far. */
947 
948 /* Return a new array of strings which is the result of appending each
949  string in ARR2 to each string in ARR1. The resultant array is
950  len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
951  are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
952  is returned. */
953 
954 static std::list<std::string>
955 array_concat (const std::list<std::string>& arr1,
956  const std::list<std::string>& arr2)
957 {
958  std::list<std::string> result;
959 
960  if (arr1.empty ())
961  result = arr2;
962  else if (arr2.empty ())
963  result = arr1;
964  else
965  {
966  for (const auto &elt_2 : arr2)
967  for (const auto &elt_1 : arr1)
968  result.push_back (elt_1 + elt_2);
969  }
970 
971  return result;
972 }
973 
974 static int brace_gobbler (const std::string&, int&, int);
975 static std::list<std::string> expand_amble (const std::string&);
976 
977 /* Return an array of strings; the brace expansion of TEXT. */
978 static std::list<std::string>
980 {
981  /* Find the text of the preamble. */
982  int i = 0;
983  int c = brace_gobbler (text, i, '{');
984 
985  std::string preamble = text.substr (0, i);
986 
987  std::list<std::string> result (1, preamble);
988 
989  if (c == '{')
990  {
991  /* Find the amble. This is the stuff inside this set of braces. */
992  int start = ++i;
993  c = brace_gobbler (text, i, '}');
994 
995  /* What if there isn't a matching close brace? */
996  if (! c)
997  {
998  (*current_liboctave_warning_with_id_handler)
999  ("Octave:pathsearch-syntax",
1000  "%s: Unmatched {", text.c_str ());
1001 
1002  result = std::list<std::string> (1, text);
1003  }
1004  else
1005  {
1006  std::string amble = text.substr (start, i-start);
1007  result = array_concat (result, expand_amble (amble));
1008 
1009  std::string postamble = text.substr (i+1);
1010  result = array_concat (result, brace_expand (postamble));
1011  }
1012  }
1013 
1014  return result;
1015 }
1016 
1017 /* The character which is used to separate arguments. */
1018 static int brace_arg_separator = ',';
1019 
1020 /* Expand the text found inside of braces. We simply try to split the
1021  text at BRACE_ARG_SEPARATORs into separate strings. We then brace
1022  expand each slot which needs it, until there are no more slots which
1023  need it. */
1024 static std::list<std::string>
1026 {
1027  std::list<std::string> result;
1028 
1029  size_t text_len = text.length ();
1030  size_t start;
1031  int i, c;
1032 
1033  for (start = 0, i = 0, c = 1; c && start < text_len; start = ++i)
1034  {
1035  int i0 = i;
1036  int c0 = brace_gobbler (text, i0, brace_arg_separator);
1037  int i1 = i;
1038  int c1 = brace_gobbler (text, i1, ENV_SEP);
1039  c = c0 | c1;
1040  i = (i0 < i1 ? i0 : i1);
1041 
1042  std::string tem = text.substr (start, i-start);
1043 
1044  std::list<std::string> partial = brace_expand (tem);
1045 
1046  if (result.empty ())
1047  result = partial;
1048  else
1049  result.splice (result.end (), partial);
1050  }
1051 
1052  return result;
1053 }
1054 
1055 /* Start at INDEX, and skip characters in TEXT. Set INDEX to the
1056  index of the character matching SATISFY. This understands about
1057  quoting. Return the character that caused us to stop searching;
1058  this is either the same as SATISFY, or 0. */
1059 static int
1060 brace_gobbler (const std::string& text, int& indx, int satisfy)
1061 {
1062  int c = 0;
1063  int level = 0;
1064  int quoted = 0;
1065  int pass_next = 0;
1066 
1067  size_t text_len = text.length ();
1068 
1069  size_t i = indx;
1070 
1071  for (; i < text_len; i++)
1072  {
1073  c = text[i];
1074 
1075  if (pass_next)
1076  {
1077  pass_next = 0;
1078  continue;
1079  }
1080 
1081  /* A backslash escapes the next character. This allows backslash to
1082  escape the quote character in a double-quoted string. */
1083  if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
1084  {
1085  pass_next = 1;
1086  continue;
1087  }
1088 
1089  if (quoted)
1090  {
1091  if (c == quoted)
1092  quoted = 0;
1093  continue;
1094  }
1095 
1096  if (c == '"' || c == '\'' || c == '`')
1097  {
1098  quoted = c;
1099  continue;
1100  }
1101 
1102  if (c == satisfy && ! level && ! quoted)
1103  {
1104  /* We ignore an open brace surrounded by whitespace, and also
1105  an open brace followed immediately by a close brace, that
1106  was preceded with whitespace. */
1107  if (c == '{'
1108  && ((i == 0 || brace_whitespace (text[i-1]))
1109  && (i+1 < text_len
1110  && (brace_whitespace (text[i+1]) || text[i+1] == '}'))))
1111  continue;
1112  /* If this is being compiled as part of bash, ignore the '{'
1113  in a '${ }' construct */
1114  if ((c != '{') || i == 0 || (text[i-1] != '$'))
1115  break;
1116  }
1117 
1118  if (c == '{')
1119  level++;
1120  else if (c == '}' && level)
1121  level--;
1122  }
1123 
1124  indx = i;
1125  return c;
1126 }
1127 
1128 /* Expand extra colons. */
1129 
1130 /* Check for leading colon first, then trailing, then doubled, since
1131  that is fastest. Usually it will be leading or trailing. */
1132 
1133 /* Replace a leading or trailing or doubled : in PATH with DFLT. If
1134  no extra colons, return PATH. Only one extra colon is replaced.
1135  DFLT may not be NULL. */
1136 
1138 kpse_expand_default (const std::string& path, const std::string& fallback)
1139 {
1140  std::string expansion;
1141 
1142  size_t path_len = path.length ();
1143 
1144  if (path_len == 0)
1145  expansion = fallback;
1146 
1147  /* Solitary or leading :? */
1148  else if (IS_ENV_SEP (path[0]))
1149  {
1150  expansion = path_len == 1 ? fallback : fallback + path;
1151  }
1152 
1153  /* Sorry about the assignment in the middle of the expression, but
1154  conventions were made to be flouted and all that. I don't see the
1155  point of calling strlen twice or complicating the logic just to
1156  avoid the assignment (especially now that I've pointed it out at
1157  such great length). */
1158  else if (IS_ENV_SEP (path[path_len-1]))
1159  expansion = path + fallback;
1160 
1161  /* OK, not leading or trailing. Check for doubled. */
1162  else
1163  {
1164  /* What we'll return if we find none. */
1165  expansion = path;
1166 
1167  for (size_t i = 0; i < path_len; i++)
1168  {
1169  if (i + 1 < path_len
1170  && IS_ENV_SEP (path[i]) && IS_ENV_SEP (path[i+1]))
1171  {
1172  /* We have a doubled colon. */
1173 
1174  /* Copy stuff up to and including the first colon. */
1175  /* Copy in FALLBACK, and then the rest of PATH. */
1176  expansion = path.substr (0, i+1) + fallback + path.substr (i+1);
1177 
1178  break;
1179  }
1180  }
1181  }
1182 
1183  return expansion;
1184 }
1185 
1186 /* Return true if FN is a directory or a symlink to a directory,
1187  false if not. */
1188 
1189 static bool
1190 dir_p (const std::string& fn)
1191 {
1193 
1194  return (fs && fs.is_dir ());
1195 }
1196 
1197 /* Given a path element ELT, return a the element with a trailing slash
1198  or an empty string if the element is not a directory.
1199 
1200  It's up to the caller to expand ELT. This is because this routine is
1201  most likely only useful to be called from 'kpse_path_search', which
1202  has already assumed expansion has been done. */
1203 
1206 {
1207  std::string ret;
1208 
1209  /* If given nothing, return nothing. */
1210  if (elt.empty ())
1211  return ret;
1212 
1213  if (dir_p (elt))
1214  {
1215  ret = elt;
1216 
1217  char last_char = ret[ret.length () - 1];
1218 
1219  if (! (IS_DIR_SEP (last_char) || IS_DEVICE_SEP (last_char)))
1220  ret += DIR_SEP_STRING;
1221  }
1222 
1223  return ret;
1224 }
1225 
1226 /* Variable expansion. */
1227 
1228 /* We have to keep track of variables being expanded, otherwise
1229  constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
1230  (Or indirectly recursive variables, etc.) Our simple solution is to
1231  add to a list each time an expansion is started, and check the list
1232  before expanding. */
1233 
1234 static std::map <std::string, bool> expansions;
1235 
1236 static void
1237 expanding (const std::string& var, bool xp)
1238 {
1239  expansions[var] = xp;
1240 }
1241 
1242 /* Return whether VAR is currently being expanding. */
1243 
1244 static bool
1246 {
1247  return (expansions.find (var) != expansions.end ()) ? expansions[var] : false;
1248 }
1249 
1250 /* Append the result of value of 'var' to EXPANSION, where 'var' begins
1251  at START and ends at END. If 'var' is not set, do not complain.
1252  This is a subroutine for the more complicated expansion function. */
1253 
1254 static void
1255 expand (std::string &expansion, const std::string& var)
1256 {
1257  if (expanding_p (var))
1258  {
1259  (*current_liboctave_warning_with_id_handler)
1260  ("Octave:pathsearch-syntax",
1261  "pathsearch: variable '%s' references itself (eventually)",
1262  var.c_str ());
1263  }
1264  else
1265  {
1266  /* Check for an environment variable. */
1268 
1269  if (! value.empty ())
1270  {
1271  expanding (var, true);
1272  std::string tmp = kpse_var_expand (value);
1273  expanding (var, false);
1274  expansion += tmp;
1275  }
1276  }
1277 }
1278 
1279 /* Can't think of when it would be useful to change these (and the
1280  diagnostic messages assume them), but ... */
1281 
1282 /* starts all variable references */
1283 #if ! defined (IS_VAR_START)
1284 # define IS_VAR_START(c) ((c) == '$')
1285 #endif
1286 
1287 /* variable name constituent */
1288 #if ! defined (IS_VAR_CHAR)
1289 # define IS_VAR_CHAR(c) (isalnum (c) || (c) == '_')
1290 #endif
1291 
1292 /* start delimited variable name (after $) */
1293 #if ! defined (IS_VAR_BEGIN_DELIMITER)
1294 # define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
1295 #endif
1296 
1297 #if ! defined (IS_VAR_END_DELIMITER)
1298 # define IS_VAR_END_DELIMITER(c) ((c) == '}')
1299 #endif
1300 
1301 /* Maybe we should support some or all of the various shell ${...}
1302  constructs, especially ${var-value}. */
1303 
1304 static std::string
1306 {
1307  std::string expansion;
1308 
1309  size_t src_len = src.length ();
1310 
1311  /* Copy everything but variable constructs. */
1312  for (size_t i = 0; i < src_len; i++)
1313  {
1314  if (IS_VAR_START (src[i]))
1315  {
1316  i++;
1317 
1318  /* Three cases: '$VAR', '${VAR}', '$<anything-else>'. */
1319  if (IS_VAR_CHAR (src[i]))
1320  {
1321  /* $V: collect name constituents, then expand. */
1322  size_t var_end = i;
1323 
1324  do
1325  {
1326  var_end++;
1327  }
1328  while (IS_VAR_CHAR (src[var_end]));
1329 
1330  var_end--; /* had to go one past */
1331  expand (expansion, src.substr (i, var_end - i + 1));
1332  i = var_end;
1333 
1334  }
1335  else if (IS_VAR_BEGIN_DELIMITER (src[i]))
1336  {
1337  /* ${: scan ahead for matching delimiter, then expand. */
1338  size_t var_end = ++i;
1339 
1340  while (var_end < src_len && ! IS_VAR_END_DELIMITER (src[var_end]))
1341  var_end++;
1342 
1343  if (var_end == src_len)
1344  {
1345  (*current_liboctave_warning_with_id_handler)
1346  ("Octave:pathsearch-syntax",
1347  "%s: No matching } for ${", src.c_str ());
1348  i = var_end - 1; /* will incr to eos at top of loop */
1349  }
1350  else
1351  {
1352  expand (expansion, src.substr (i, var_end - i));
1353  i = var_end; /* will incr past } at top of loop*/
1354  }
1355  }
1356  else
1357  {
1358  /* $<something-else>: error. */
1359  (*current_liboctave_warning_with_id_handler)
1360  ("Octave:pathsearch-syntax",
1361  "%s: Unrecognized variable construct '$%c'",
1362  src.c_str (), src[i]);
1363 
1364  /* Just ignore those chars and keep going. */
1365  }
1366  }
1367  else
1368  expansion += src[i];
1369  }
1370 
1371  return expansion;
1372 }
static password getpwnam(const std::string &nm)
Definition: oct-passwd.cc:152
size_t len
Definition: kpse.h:60
#define IS_VAR_BEGIN_DELIMITER(c)
Definition: kpse.cc:1294
std::list< std::string > kpse_all_path_find_first_of(const std::string &path, const std::list< std::string > &names)
Definition: kpse.cc:644
time_t unix_time(void) const
Definition: oct-time.h:95
const std::string & path
Definition: kpse.h:57
static bool dir_p(const std::string &fn)
Definition: kpse.cc:1190
#define ENV_SEP_STRING
Definition: kpse.cc:68
static bool is_path_sep(char c)
Definition: pathsearch.h:114
static int brace_gobbler(const std::string &, int &, int)
Definition: kpse.cc:1060
in that an updated permutation matrix is returned Note that if var
Definition: lu.cc:606
static void expand(std::string &expansion, const std::string &var)
Definition: kpse.cc:1255
static std::list< std::string > expand_amble(const std::string &)
Definition: kpse.cc:1025
octave_idx_type length(void) const
Definition: ovl.h:96
static std::string kpse_brace_expand_element(const std::string &elt)
Definition: kpse.cc:798
#define ENV_SEP
Definition: kpse.cc:67
octave::sys::time now
Definition: data.cc:6299
#define brace_whitespace(c)
Definition: kpse.cc:938
static bool expanding_p(const std::string &var)
Definition: kpse.cc:1245
static bool first_search
Definition: kpse.cc:257
#define IS_VAR_START(c)
Definition: kpse.cc:1284
static std::string kpse_readable_file(const std::string &name)
Definition: kpse.cc:203
static std::list< std::string > absolute_search(const std::string &name)
Definition: kpse.cc:309
std::string kpse_path_expand(const std::string &path)
Definition: kpse.cc:867
std::string filename
Definition: urlwrite.cc:340
static bool rooted_relative_pathname(const std::string &s)
Definition: oct-env.cc:115
#define KPSE_DEBUG_SEARCH
Definition: kpse.cc:82
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
static std::map< std::string, bool > expansions
Definition: kpse.cc:1234
std::list< std::string > path_find_first_of(const std::string &path, const std::list< std::string > &names, bool all)
Definition: kpse.cc:477
s
Definition: file-io.cc:2682
static void log_search(const std::list< std::string > &filenames)
Definition: kpse.cc:262
int octave_access_wrapper(const char *nm, int mode)
std::string kpse_path_search(const std::string &path, const std::string &name)
Definition: kpse.cc:456
static std::list< std::string > array_concat(const std::list< std::string > &arr1, const std::list< std::string > &arr2)
Definition: kpse.cc:955
static std::string getenv(const std::string &name)
Definition: oct-env.cc:235
static std::list< std::string > brace_expand(const std::string &)
Definition: kpse.cc:979
size_t e
Definition: kpse.h:59
int octave_access_r_ok(void)
void set_end(void)
Definition: kpse.cc:95
OCTAVE_EXPORT octave_value_list search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:302
#define IS_VAR_CHAR(c)
Definition: kpse.cc:1289
std::string kpse_path_find_first_of(const std::string &path, const std::list< std::string > &names)
Definition: kpse.cc:628
bool is_dir(void) const
Definition: file-stat.cc:57
#define IS_DIR_SEP(ch)
Definition: kpse.cc:65
done
Definition: syscalls.cc:248
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
std::string dir(void) const
Definition: oct-passwd.cc:96
static std::string get_home_directory(void)
Definition: oct-env.cc:143
static bool absolute_pathname(const std::string &s)
Definition: oct-env.cc:108
std::string kpse_expand_default(const std::string &path, const std::string &fallback)
Definition: kpse.cc:1138
double tmp
Definition: data.cc:6300
static std::string kpse_expand(const std::string &s)
Definition: kpse.cc:746
octave_value retval
Definition: data.cc:6294
unsigned int kpse_debug
Definition: kpse.cc:88
static std::string kpse_tilde_expand(const std::string &name)
Definition: kpse.cc:655
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:395
std::list< std::string > kpse_all_path_search(const std::string &path, const std::string &name)
Definition: kpse.cc:467
void next(void)
Definition: kpse.cc:114
static std::list< std::string > find_first_of(const std::string &path, const std::list< std::string > &names, bool all)
Definition: kpse.cc:548
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
#define KPSE_DEBUG_P(bit)
Definition: kpse.cc:78
With real return the complex result
Definition: data.cc:3375
OCTAVE_EXPORT octave_value_list the first data row corresponds to an index of zero The a spreadsheet style form such as the file is read until end of file is reached The such as text
Definition: dlmread.cc:191
octave::sys::time start
Definition: graphics.cc:11731
#define NAME_BEGINS_WITH_DEVICE(name)
Definition: kpse.cc:61
static std::list< std::string > path_search(const std::string &path, const std::string &name, bool all)
Definition: kpse.cc:325
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
static int brace_arg_separator
Definition: kpse.cc:1018
static std::string kpse_var_expand(const std::string &src)
Definition: kpse.cc:1305
static std::list< std::string > dir_search(const std::string &dir, const std::string &name, bool search_all)
Definition: kpse.cc:285
#define DIR_SEP_STRING
Definition: kpse.cc:64
octave::sys::file_stat fs(filename)
static std::string kpse_brace_expand(const std::string &path)
Definition: kpse.cc:831
static std::string kpse_truncate_filename(const std::string &name)
Definition: kpse.cc:132
#define IS_VAR_END_DELIMITER(c)
Definition: kpse.cc:1298
static bool READABLE(const std::string &fn)
Definition: kpse.cc:179
size_t b
Definition: kpse.h:58
std::string kpse_element_dir(const std::string &elt)
Definition: kpse.cc:1205
static std::string kpse_expand_kpse_dot(const std::string &path)
Definition: kpse.cc:759
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
#define IS_DEVICE_SEP(ch)
Definition: kpse.cc:60
static unsigned int max_name_length(void)
Definition: dir-ops.cc:105
static void expanding(const std::string &var, bool xp)
Definition: kpse.cc:1237
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
static const double pi
Definition: lo-specfun.cc:3610
static bool kpse_absolute_p(const std::string &filename, int relative_ok)
Definition: kpse.cc:244
#define IS_ENV_SEP(ch)
Definition: kpse.cc:69