GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
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-2018 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
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17 
18 Octave is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License 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 <https://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 
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  {
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 {
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
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 () : ".");
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.back ()))
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  if (! ret.empty ())
786  ret.pop_back ();
787 
788  return ret;
789 }
790 
791 /* Do brace expansion on ELT; then do variable and ~ expansion on each
792  element of the result; then do brace expansion again, in case a
793  variable definition contained braces (e.g., $TEXMF). Return a
794  string comprising all of the results separated by ENV_SEP_STRING. */
795 
796 static std::string
798 {
799  std::string ret;
800 
801  std::list<std::string> expansions = brace_expand (elt);
802 
803  for (const auto& expanded_elt : expansions)
804  {
805  /* Do $ and ~ expansion on each element. */
806  std::string x = kpse_expand (expanded_elt);
807 
808  if (x != elt)
809  {
810  /* If we did any expansions, do brace expansion again. Since
811  recursive variable definitions are not allowed, this recursion
812  must terminate. (In practice, it's unlikely there will ever be
813  more than one level of recursion.) */
815  }
816 
817  ret += x + ENV_SEP_STRING;
818  }
819 
820  ret.pop_back ();
821 
822  return ret;
823 }
824 
825 /* Do brace expansion and call 'kpse_expand' on each element of the
826  result; return the final expansion (always in fresh memory, even if
827  no expansions were done). */
828 
829 static std::string
831 {
832  /* Must do variable expansion first because if we have
833  foo = .:~
834  TEXINPUTS = $foo
835  we want to end up with TEXINPUTS = .:/home/karl.
836  Since kpse_path_element is not reentrant, we must get all
837  the path elements before we start the loop. */
839 
840  std::string ret;
841 
842  for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
843  {
844  std::string elt = *pi;
845 
846  /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}. */
847  std::string expansion = kpse_brace_expand_element (elt);
848  ret += expansion + ENV_SEP_STRING;
849  }
850 
851  if (! ret.empty ())
852  ret.pop_back ();
853 
854  return kpse_expand_kpse_dot (ret);
855 }
856 
857 /* Expand all special constructs in a path, and include only the actually
858  existing directories in the result. */
859 
860 /* Do brace expansion and call 'kpse_expand' on each argument of the
861  result. The final expansion (always in fresh memory) is a path of
862  all the existing directories that match the pattern. */
863 
866 {
867  std::string ret;
868  unsigned len;
869 
870  len = 0;
871 
872  /* Expand variables and braces first. */
874 
875  /* Now expand each of the path elements, printing the results */
876  for (kpse_path_iterator pi (tmp); pi != std::string::npos; pi++)
877  {
878  std::string elt = *pi;
879 
880  std::string dir;
881 
882  /* Do not touch the device if present */
883  if (NAME_BEGINS_WITH_DEVICE (elt))
884  {
885  while (elt.length () > 3
886  && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
887  {
888  elt[2] = elt[1];
889  elt[1] = elt[0];
890  elt = elt.substr (1);
891  }
892  }
893  else
894  {
895  /* We never want to search the whole disk. */
896  while (elt.length () > 1
897  && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
898  elt = elt.substr (1);
899  }
900 
901  /* Search the disk for all dirs in the component specified.
902  Be faster to check the database, but this is more reliable. */
903  dir = kpse_element_dir (elt);
904 
905  size_t dirlen = dir.length ();
906 
907  if (dirlen > 0)
908  {
909  ret += dir;
910  len += dirlen;
911 
912  /* Retain trailing slash if that's the root directory. */
913  if (dirlen == 1
914  || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (dir)
915  && IS_DIR_SEP (dir[2])))
916  {
917  ret += ENV_SEP_STRING;
918  len++;
919  }
920 
921  ret[len-1] = ENV_SEP;
922  }
923  }
924 
925  if (! ret.empty ())
926  ret.pop_back ();
927 
928  return ret;
929 }
930 
931 /* braces.c -- code for doing word expansion in curly braces. Taken from
932  bash 1.14.5. [And subsequently modified for kpatshea.]
933 
934  Copyright (C) 1987,1991 Free Software Foundation, Inc. */
935 
936 #define brace_whitespace(c) (! (c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
937 
938 /* Basic idea:
939 
940  Segregate the text into 3 sections: preamble (stuff before an open brace),
941  postamble (stuff after the matching close brace) and amble (stuff after
942  preamble, and before postamble). Expand amble, and then tack on the
943  expansions to preamble. Expand postamble, and tack on the expansions to
944  the result so far. */
945 
946 /* Return a new array of strings which is the result of appending each
947  string in ARR2 to each string in ARR1. The resultant array is
948  len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
949  are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
950  is returned. */
951 
952 static std::list<std::string>
953 array_concat (const std::list<std::string>& arr1,
954  const std::list<std::string>& arr2)
955 {
956  std::list<std::string> result;
957 
958  if (arr1.empty ())
959  result = arr2;
960  else if (arr2.empty ())
961  result = arr1;
962  else
963  {
964  for (const auto& elt_2 : arr2)
965  for (const auto& elt_1 : arr1)
966  result.push_back (elt_1 + elt_2);
967  }
968 
969  return result;
970 }
971 
972 static int brace_gobbler (const std::string&, int&, int);
973 static std::list<std::string> expand_amble (const std::string&);
974 
975 /* Return an array of strings; the brace expansion of TEXT. */
976 static std::list<std::string>
978 {
979  /* Find the text of the preamble. */
980  int i = 0;
981  int c = brace_gobbler (text, i, '{');
982 
983  std::string preamble = text.substr (0, i);
984 
985  std::list<std::string> result (1, preamble);
986 
987  if (c == '{')
988  {
989  /* Find the amble. This is the stuff inside this set of braces. */
990  int start = ++i;
991  c = brace_gobbler (text, i, '}');
992 
993  /* What if there isn't a matching close brace? */
994  if (! c)
995  {
996  (*current_liboctave_warning_with_id_handler)
997  ("Octave:pathsearch-syntax",
998  "%s: Unmatched {", text.c_str ());
999 
1000  result = std::list<std::string> (1, text);
1001  }
1002  else
1003  {
1004  std::string amble = text.substr (start, i-start);
1005  result = array_concat (result, expand_amble (amble));
1006 
1007  std::string postamble = text.substr (i+1);
1008  result = array_concat (result, brace_expand (postamble));
1009  }
1010  }
1011 
1012  return result;
1013 }
1014 
1015 /* The character which is used to separate arguments. */
1016 static int brace_arg_separator = ',';
1017 
1018 /* Expand the text found inside of braces. We simply try to split the
1019  text at BRACE_ARG_SEPARATORs into separate strings. We then brace
1020  expand each slot which needs it, until there are no more slots which
1021  need it. */
1022 static std::list<std::string>
1024 {
1025  std::list<std::string> result;
1026 
1027  size_t text_len = text.length ();
1028  size_t start;
1029  int i, c;
1030 
1031  for (start = 0, i = 0, c = 1; c && start < text_len; start = ++i)
1032  {
1033  int i0 = i;
1034  int c0 = brace_gobbler (text, i0, brace_arg_separator);
1035  int i1 = i;
1036  int c1 = brace_gobbler (text, i1, ENV_SEP);
1037  c = c0 | c1;
1038  i = (i0 < i1 ? i0 : i1);
1039 
1040  std::string tem = text.substr (start, i-start);
1041 
1042  std::list<std::string> partial = brace_expand (tem);
1043 
1044  if (result.empty ())
1045  result = partial;
1046  else
1047  result.splice (result.end (), partial);
1048  }
1049 
1050  return result;
1051 }
1052 
1053 /* Start at INDEX, and skip characters in TEXT. Set INDEX to the
1054  index of the character matching SATISFY. This understands about
1055  quoting. Return the character that caused us to stop searching;
1056  this is either the same as SATISFY, or 0. */
1057 static int
1058 brace_gobbler (const std::string& text, int& indx, int satisfy)
1059 {
1060  int c = 0;
1061  int level = 0;
1062  int quoted = 0;
1063  int pass_next = 0;
1064 
1065  size_t text_len = text.length ();
1066 
1067  size_t i = indx;
1068 
1069  for (; i < text_len; i++)
1070  {
1071  c = text[i];
1072 
1073  if (pass_next)
1074  {
1075  pass_next = 0;
1076  continue;
1077  }
1078 
1079  /* A backslash escapes the next character. This allows backslash to
1080  escape the quote character in a double-quoted string. */
1081  if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
1082  {
1083  pass_next = 1;
1084  continue;
1085  }
1086 
1087  if (quoted)
1088  {
1089  if (c == quoted)
1090  quoted = 0;
1091  continue;
1092  }
1093 
1094  if (c == '"' || c == '\'' || c == '`')
1095  {
1096  quoted = c;
1097  continue;
1098  }
1099 
1100  if (c == satisfy && ! level && ! quoted)
1101  {
1102  /* We ignore an open brace surrounded by whitespace, and also
1103  an open brace followed immediately by a close brace, that
1104  was preceded with whitespace. */
1105  if (c == '{'
1106  && ((i == 0 || brace_whitespace (text[i-1]))
1107  && (i+1 < text_len
1108  && (brace_whitespace (text[i+1]) || text[i+1] == '}'))))
1109  continue;
1110  /* If this is being compiled as part of bash, ignore the '{'
1111  in a '${ }' construct */
1112  if ((c != '{') || i == 0 || (text[i-1] != '$'))
1113  break;
1114  }
1115 
1116  if (c == '{')
1117  level++;
1118  else if (c == '}' && level)
1119  level--;
1120  }
1121 
1122  indx = i;
1123  return c;
1124 }
1125 
1126 /* Expand extra colons. */
1127 
1128 /* Check for leading colon first, then trailing, then doubled, since
1129  that is fastest. Usually it will be leading or trailing. */
1130 
1131 /* Replace a leading or trailing or doubled : in PATH with DFLT. If
1132  no extra colons, return PATH. Only one extra colon is replaced.
1133  DFLT may not be NULL. */
1134 
1136 kpse_expand_default (const std::string& path, const std::string& fallback)
1137 {
1138  std::string expansion;
1139 
1140  size_t path_len = path.length ();
1141 
1142  if (path_len == 0)
1143  expansion = fallback;
1144 
1145  /* Solitary or leading :? */
1146  else if (IS_ENV_SEP (path[0]))
1147  {
1148  expansion = (path_len == 1 ? fallback : fallback + path);
1149  }
1150 
1151  /* Sorry about the assignment in the middle of the expression, but
1152  conventions were made to be flouted and all that. I don't see the
1153  point of calling strlen twice or complicating the logic just to
1154  avoid the assignment (especially now that I've pointed it out at
1155  such great length). */
1156  else if (IS_ENV_SEP (path[path_len-1]))
1157  expansion = path + fallback;
1158 
1159  /* OK, not leading or trailing. Check for doubled. */
1160  else
1161  {
1162  /* What we'll return if we find none. */
1163  expansion = path;
1164 
1165  for (size_t i = 0; i < path_len; i++)
1166  {
1167  if (i + 1 < path_len
1168  && IS_ENV_SEP (path[i]) && IS_ENV_SEP (path[i+1]))
1169  {
1170  /* We have a doubled colon. */
1171 
1172  /* Copy stuff up to and including the first colon. */
1173  /* Copy in FALLBACK, and then the rest of PATH. */
1174  expansion = path.substr (0, i+1) + fallback + path.substr (i+1);
1175 
1176  break;
1177  }
1178  }
1179  }
1180 
1181  return expansion;
1182 }
1183 
1184 /* Return true if FN is a directory or a symlink to a directory,
1185  false if not. */
1186 
1187 static bool
1188 dir_p (const std::string& fn)
1189 {
1191 
1192  return (fs && fs.is_dir ());
1193 }
1194 
1195 /* Given a path element ELT, return a the element with a trailing slash
1196  or an empty string if the element is not a directory.
1197 
1198  It's up to the caller to expand ELT. This is because this routine is
1199  most likely only useful to be called from 'kpse_path_search', which
1200  has already assumed expansion has been done. */
1201 
1204 {
1205  std::string ret;
1206 
1207  /* If given nothing, return nothing. */
1208  if (elt.empty ())
1209  return ret;
1210 
1211  if (dir_p (elt))
1212  {
1213  ret = elt;
1214 
1215  char last_char = ret.back ();
1216 
1217  if (! (IS_DIR_SEP (last_char) || IS_DEVICE_SEP (last_char)))
1218  ret += DIR_SEP_STRING;
1219  }
1220 
1221  return ret;
1222 }
1223 
1224 /* Variable expansion. */
1225 
1226 /* We have to keep track of variables being expanded, otherwise
1227  constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
1228  (Or indirectly recursive variables, etc.) Our simple solution is to
1229  add to a list each time an expansion is started, and check the list
1230  before expanding. */
1231 
1232 static std::map <std::string, bool> expansions;
1233 
1234 static void
1235 expanding (const std::string& var, bool xp)
1236 {
1237  expansions[var] = xp;
1238 }
1239 
1240 /* Return whether VAR is currently being expanding. */
1241 
1242 static bool
1244 {
1245  return (expansions.find (var) != expansions.end ()) ? expansions[var] : false;
1246 }
1247 
1248 /* Append the result of value of 'var' to EXPANSION, where 'var' begins
1249  at START and ends at END. If 'var' is not set, do not complain.
1250  This is a subroutine for the more complicated expansion function. */
1251 
1252 static void
1253 expand (std::string& expansion, const std::string& var)
1254 {
1255  if (expanding_p (var))
1256  {
1257  (*current_liboctave_warning_with_id_handler)
1258  ("Octave:pathsearch-syntax",
1259  "pathsearch: variable '%s' references itself (eventually)",
1260  var.c_str ());
1261  }
1262  else
1263  {
1264  /* Check for an environment variable. */
1266 
1267  if (! value.empty ())
1268  {
1269  expanding (var, true);
1271  expanding (var, false);
1272  expansion += tmp;
1273  }
1274  }
1275 }
1276 
1277 /* Can't think of when it would be useful to change these (and the
1278  diagnostic messages assume them), but ... */
1279 
1280 /* starts all variable references */
1281 #if ! defined (IS_VAR_START)
1282 # define IS_VAR_START(c) ((c) == '$')
1283 #endif
1284 
1285 /* variable name constituent */
1286 #if ! defined (IS_VAR_CHAR)
1287 # define IS_VAR_CHAR(c) (isalnum (c) || (c) == '_')
1288 #endif
1289 
1290 /* start delimited variable name (after $) */
1291 #if ! defined (IS_VAR_BEGIN_DELIMITER)
1292 # define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
1293 #endif
1294 
1295 #if ! defined (IS_VAR_END_DELIMITER)
1296 # define IS_VAR_END_DELIMITER(c) ((c) == '}')
1297 #endif
1298 
1299 /* Maybe we should support some or all of the various shell ${...}
1300  constructs, especially ${var-value}. */
1301 
1302 static std::string
1304 {
1305  std::string expansion;
1306 
1307  size_t src_len = src.length ();
1308 
1309  /* Copy everything but variable constructs. */
1310  for (size_t i = 0; i < src_len; i++)
1311  {
1312  if (IS_VAR_START (src[i]))
1313  {
1314  i++;
1315 
1316  /* Three cases: '$VAR', '${VAR}', '$<anything-else>'. */
1317  if (IS_VAR_CHAR (src[i]))
1318  {
1319  /* $V: collect name constituents, then expand. */
1320  size_t var_end = i;
1321 
1322  do
1323  {
1324  var_end++;
1325  }
1326  while (IS_VAR_CHAR (src[var_end]));
1327 
1328  var_end--; /* had to go one past */
1329  expand (expansion, src.substr (i, var_end - i + 1));
1330  i = var_end;
1331 
1332  }
1333  else if (IS_VAR_BEGIN_DELIMITER (src[i]))
1334  {
1335  /* ${: scan ahead for matching delimiter, then expand. */
1336  size_t var_end = ++i;
1337 
1338  while (var_end < src_len && ! IS_VAR_END_DELIMITER (src[var_end]))
1339  var_end++;
1340 
1341  if (var_end == src_len)
1342  {
1343  (*current_liboctave_warning_with_id_handler)
1344  ("Octave:pathsearch-syntax",
1345  "%s: No matching } for ${", src.c_str ());
1346  i = var_end - 1; /* will incr to eos at top of loop */
1347  }
1348  else
1349  {
1350  expand (expansion, src.substr (i, var_end - i));
1351  i = var_end; /* will incr past } at top of loop*/
1352  }
1353  }
1354  else
1355  {
1356  /* $<something-else>: error. */
1357  (*current_liboctave_warning_with_id_handler)
1358  ("Octave:pathsearch-syntax",
1359  "%s: Unrecognized variable construct '$%c'",
1360  src.c_str (), src[i]);
1361 
1362  /* Just ignore those chars and keep going. */
1363  }
1364  }
1365  else
1366  expansion += src[i];
1367  }
1368 
1369  return expansion;
1370 }
static password getpwnam(const std::string &nm)
Definition: oct-passwd.cc:154
size_t len
Definition: kpse.h:60
#define IS_VAR_BEGIN_DELIMITER(c)
Definition: kpse.cc:1292
std::list< std::string > kpse_all_path_find_first_of(const std::string &path, const std::list< std::string > &names)
Definition: kpse.cc:644
is already an absolute the name is checked against the file system instead of Octave s loadpath In this if otherwise an empty string is returned If the first argument is a cell array of 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:305
const std::string & path
Definition: kpse.h:57
static bool dir_p(const std::string &fn)
Definition: kpse.cc:1188
#define ENV_SEP_STRING
Definition: kpse.cc:68
static bool is_path_sep(char c)
Definition: pathsearch.h:81
static int brace_gobbler(const std::string &, int &, int)
Definition: kpse.cc:1058
static void expand(std::string &expansion, const std::string &var)
Definition: kpse.cc:1253
static std::list< std::string > expand_amble(const std::string &)
Definition: kpse.cc:1023
static std::string kpse_brace_expand_element(const std::string &elt)
Definition: kpse.cc:797
#define ENV_SEP
Definition: kpse.cc:67
octave::sys::time now
Definition: data.cc:6251
#define brace_whitespace(c)
Definition: kpse.cc:936
static bool expanding_p(const std::string &var)
Definition: kpse.cc:1243
static bool first_search
Definition: kpse.cc:257
#define IS_VAR_START(c)
Definition: kpse.cc:1282
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:865
std::string filename
Definition: urlwrite.cc:121
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:997
static std::map< std::string, bool > expansions
Definition: kpse.cc:1232
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
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:2729
var
Definition: givens.cc:88
static void log_search(const std::list< std::string > &filenames)
Definition: kpse.cc:262
int octave_access_wrapper(const char *nm, int mode)
bool is_dir(void) const
Definition: file-stat.cc:57
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:953
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:977
size_t e
Definition: kpse.h:59
int octave_access_r_ok(void)
void set_end(void)
Definition: kpse.cc:95
#define IS_VAR_CHAR(c)
Definition: kpse.cc:1287
std::string kpse_path_find_first_of(const std::string &path, const std::list< std::string > &names)
Definition: kpse.cc:628
#define IS_DIR_SEP(ch)
Definition: kpse.cc:65
done
Definition: syscalls.cc:251
nd deftypefn *std::string name
Definition: sysdep.cc:647
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:1136
double tmp
Definition: data.cc:6252
static std::string kpse_expand(const std::string &s)
Definition: kpse.cc:746
octave_value retval
Definition: data.cc:6246
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
time_t unix_time(void) const
Definition: oct-time.h:110
#define KPSE_DEBUG_P(bit)
Definition: kpse.cc:78
With real return the complex result
Definition: data.cc:3260
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:194
octave::sys::time start
Definition: graphics.cc:12337
#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
p
Definition: lu.cc:138
static int brace_arg_separator
Definition: kpse.cc:1016
static std::string kpse_var_expand(const std::string &src)
Definition: kpse.cc:1303
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:830
for i
Definition: data.cc:5264
static std::string kpse_truncate_filename(const std::string &name)
Definition: kpse.cc:132
#define IS_VAR_END_DELIMITER(c)
Definition: kpse.cc:1296
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:1203
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:888
nd group nd example For each display the value
Definition: sysdep.cc:866
#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:1235
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 const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE * x
static const double pi
Definition: lo-specfun.cc:1996
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