00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #if defined (HAVE_CONFIG_H)
00025 #include <config.h>
00026 #endif
00027
00028 #include <map>
00029 #include <string>
00030
00031
00032
00033
00034
00035
00036
00037 #if defined (DOS) || defined (OS2) || defined (WIN32) || defined(__MSDOS__)
00038 #define DOSISH
00039 #endif
00040
00041 #if defined (DOSISH)
00042 #define MONOCASE_FILENAMES
00043 #endif
00044
00045 extern "C" {
00046 #if defined(__MINGW32__)
00047 #include <windows.h>
00048 #include <fcntl.h>
00049 #include <dirent.h>
00050 #elif defined(WIN32)
00051 #define __STDC__ 1
00052 #include "win32lib.h"
00053 #endif
00054
00055 #ifdef __DJGPP__
00056 #include <fcntl.h>
00057 #include <dir.h>
00058 #include <io.h>
00059 #endif
00060 }
00061
00062
00063 #ifndef KPATHSEA
00064 #define KPATHSEA 32
00065 #endif
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #if !defined (DOSISH) || defined(__DJGPP__)
00077
00078 #define ST_NLINK_TRICK
00079 #endif
00080
00081 #ifdef OS2
00082 #define access ln_access
00083 #define fopen ln_fopen
00084 #define rename ln_rename
00085 #define stat ln_stat
00086 #endif
00087
00088 #include "kpse-xfns.h"
00089
00090 #include "lo-error.h"
00091 #include "lo-sstream.h"
00092 #include "oct-env.h"
00093 #include "oct-passwd.h"
00094 #include "str-vec.h"
00095
00096
00097
00098
00099 #include <cstdio>
00100 #include <cstdarg>
00101 #include <cstdlib>
00102 #include <climits>
00103 #include <cerrno>
00104 #include <cassert>
00105
00106 #ifdef HAVE_UNISTD_H
00107 #ifdef HAVE_SYS_TYPES_H
00108 #include <sys/types.h>
00109 #endif
00110 #include <unistd.h>
00111 #endif
00112
00113 #include "sysdir.h"
00114 #include "statdefs.h"
00115
00116
00117
00118
00119
00120
00121
00122 #ifndef _POSIX_NAME_MAX
00123 #define _POSIX_NAME_MAX 255
00124 #endif
00125
00126 #ifndef NAME_MAX
00127 #define NAME_MAX _POSIX_NAME_MAX
00128 #endif
00129
00130 #include <cctype>
00131
00132
00133 #ifndef ENV_SEP
00134 #ifdef DOSISH
00135 #define ENV_SEP ';'
00136 #define ENV_SEP_STRING ";"
00137 #else
00138 #define ENV_SEP ':'
00139 #define ENV_SEP_STRING ":"
00140 #endif
00141 #endif
00142
00143 #ifndef IS_ENV_SEP
00144 #define IS_ENV_SEP(ch) ((ch) == ENV_SEP)
00145 #endif
00146
00147
00148
00149
00150
00151
00152
00153
00154 #ifndef _POSIX_PATH_MAX
00155 #define _POSIX_PATH_MAX 255
00156 #endif
00157
00158 #ifndef PATH_MAX
00159 #ifdef MAXPATHLEN
00160 #define PATH_MAX MAXPATHLEN
00161 #else
00162 #define PATH_MAX _POSIX_PATH_MAX
00163 #endif
00164 #endif
00165
00166
00167 #ifndef NO_DEBUG
00168
00169
00170 #define KPSE_DEBUG
00171
00172
00173 #define KPSE_DEBUG_P(bit) (kpathsea_debug & (1 << (bit)))
00174
00175 #define KPSE_DEBUG_STAT 0
00176 #define KPSE_DEBUG_HASH 1
00177 #define KPSE_DEBUG_FOPEN 2
00178 #define KPSE_DEBUG_PATHS 3
00179 #define KPSE_DEBUG_EXPAND 4
00180 #define KPSE_DEBUG_SEARCH 5
00181 #define KPSE_DEBUG_VARS 6
00182 #define KPSE_LAST_DEBUG KPSE_DEBUG_VARS
00183
00184
00185 #define DEBUGF_START() do { fputs ("kdebug:", stderr)
00186 #define DEBUGF_END() fflush (stderr); } while (0)
00187
00188 #define DEBUGF(str) \
00189 DEBUGF_START (); fputs (str, stderr); DEBUGF_END ()
00190 #define DEBUGF1(str, e1) \
00191 DEBUGF_START (); fprintf (stderr, str, e1); DEBUGF_END ()
00192 #define DEBUGF2(str, e1, e2) \
00193 DEBUGF_START (); fprintf (stderr, str, e1, e2); DEBUGF_END ()
00194 #define DEBUGF3(str, e1, e2, e3) \
00195 DEBUGF_START (); fprintf (stderr, str, e1, e2, e3); DEBUGF_END ()
00196 #define DEBUGF4(str, e1, e2, e3, e4) \
00197 DEBUGF_START (); fprintf (stderr, str, e1, e2, e3, e4); DEBUGF_END ()
00198
00199 #undef fopen
00200 #define fopen kpse_fopen_trace
00201 static FILE *fopen (const char *filename, const char *mode);
00202
00203 #endif
00204
00205 #ifdef KPSE_DEBUG
00206 static unsigned int kpathsea_debug = 0;
00207 #endif
00208
00209 #if defined (WIN32) && !defined (__MINGW32__)
00210
00211
00212
00213
00214
00215
00216
00217
00218 #ifndef DOSISH
00219 #define DOSISH
00220 #endif
00221
00222 #ifndef MAXPATHLEN
00223 #define MAXPATHLEN _MAX_PATH
00224 #endif
00225
00226
00227
00228
00229 #define access _access
00230 #define stat _stat
00231 #define strdup _strdup
00232
00233 #define S_IFMT _S_IFMT
00234 #define S_IFDIR _S_IFDIR
00235
00236
00237
00238
00239 #define _WINSOCKAPI_ 1
00240
00241 #include <windows.h>
00242
00243
00244 #include <io.h>
00245 #include <fcntl.h>
00246 #include <process.h>
00247
00248
00249
00250 #endif
00251
00252
00253
00254
00255
00256
00257 #define FATAL_PERROR(str) \
00258 do \
00259 { \
00260 fputs ("pathsearch: ", stderr); \
00261 perror (str); exit (EXIT_FAILURE); \
00262 } \
00263 while (0)
00264
00265 #define FATAL(str) \
00266 do \
00267 { \
00268 fputs ("pathsearch: fatal: ", stderr); \
00269 fputs (str, stderr); \
00270 fputs (".\n", stderr); \
00271 exit (1); \
00272 } \
00273 while (0)
00274
00275 #ifndef WIN32
00276 static void xclosedir (DIR *d);
00277 #endif
00278
00279
00280
00281
00282
00283
00284 struct str_llist_elt
00285 {
00286 std::string str;
00287 int moved;
00288 struct str_llist_elt *next;
00289 };
00290
00291 typedef str_llist_elt str_llist_elt_type;
00292 typedef str_llist_elt *str_llist_type;
00293
00294 #define STR_LLIST(sl) ((sl).str)
00295 #define STR_LLIST_MOVED(sl) ((sl).moved)
00296 #define STR_LLIST_NEXT(sl) ((sl).next)
00297
00298 static void str_llist_add (str_llist_type *l, const std::string& str);
00299
00300 static void str_llist_float (str_llist_type *l, str_llist_elt_type *mover);
00301
00302 static std::string kpse_var_expand (const std::string& src);
00303
00304 static str_llist_type *kpse_element_dirs (const std::string& elt);
00305
00306 static std::string kpse_expand (const std::string& s);
00307
00308 static std::string kpse_expand_default (const std::string& path,
00309 const std::string& dflt);
00310
00311 static string_vector kpse_db_search (const std::string& name,
00312 const std::string& path_elt, bool all);
00313
00314 #include <ctime>
00315
00316 static bool
00317 kpse_is_env_sep (char c)
00318 {
00319 return IS_ENV_SEP (c);
00320 }
00321
00322
00323
00324
00325 static FILE *
00326 xfopen (const std::string& filename, const char *mode)
00327 {
00328 FILE *f;
00329
00330 assert (! filename.empty () && mode);
00331
00332 f = fopen (filename.c_str (), mode);
00333
00334 if (! f)
00335 FATAL_PERROR (filename.c_str ());
00336
00337 return f;
00338 }
00339
00340
00341
00342 struct hash_element_type
00343 {
00344 std::string key;
00345 std::string value;
00346 struct hash_element_type *next;
00347 };
00348
00349
00350
00351 struct hash_table_type
00352 {
00353 hash_element_type **buckets;
00354 unsigned size;
00355 };
00356
00357 static unsigned
00358 hash (hash_table_type table, const std::string& key)
00359 {
00360 unsigned n = 0;
00361
00362
00363
00364 size_t len = key.length ();
00365 for (size_t i = 0; i < len; i++)
00366 n = (n + n + key[i]) % table.size;
00367
00368 return n;
00369 }
00370
00371
00372
00373
00374 static string_vector
00375 hash_lookup (hash_table_type table, const std::string& key)
00376 {
00377 hash_element_type *p;
00378 string_vector ret;
00379 unsigned n = hash (table, key);
00380
00381
00382 for (p = table.buckets[n]; p; p = p->next)
00383 if (key == p->key)
00384 ret.append (p->value);
00385
00386 #ifdef KPSE_DEBUG
00387 if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
00388 {
00389 DEBUGF1 ("hash_lookup (%s) =>", key.c_str ());
00390 if (ret.empty ())
00391 fputs (" (nil)\n", stderr);
00392 else
00393 {
00394 int len = ret.length ();
00395 for (int i = 0; i < len; i++)
00396 {
00397 putc (' ', stderr);
00398 fputs (ret[i].c_str (), stderr);
00399 }
00400 putc ('\n', stderr);
00401 }
00402 fflush (stderr);
00403 }
00404 #endif
00405
00406 return ret;
00407 }
00408
00409
00410
00411
00412 class kpse_path_iterator
00413 {
00414 public:
00415
00416 kpse_path_iterator (const std::string& p)
00417 : path (p), b (0), e (0), len (path.length ()) { set_end (); }
00418
00419 kpse_path_iterator (const kpse_path_iterator& pi)
00420 : path (pi.path), b (pi.b), e (pi.e), len (pi.len) { }
00421
00422 kpse_path_iterator operator ++ (int)
00423 {
00424 kpse_path_iterator retval (*this);
00425 next ();
00426 return retval;
00427 }
00428
00429 std::string operator * (void) { return path.substr (b, e-b); }
00430
00431 bool operator != (const size_t sz) { return b != sz; }
00432
00433 private:
00434
00435 const std::string& path;
00436 size_t b;
00437 size_t e;
00438 size_t len;
00439
00440 void set_end (void)
00441 {
00442 e = b + 1;
00443
00444 if (e == len)
00445 ;
00446 else if (e > len)
00447 b = e = NPOS;
00448 else
00449 {
00450
00451
00452
00453 int brace_level = 0;
00454 while (e < len && ! (brace_level == 0 && kpse_is_env_sep (path[e])))
00455 e++;
00456 }
00457 }
00458
00459 void next (void)
00460 {
00461 b = e + 1;
00462
00463
00464 while (kpse_is_env_sep (path[b]) && b < len)
00465 b++;
00466
00467 if (b >= len)
00468 b = e = NPOS;
00469 else
00470 set_end ();
00471 }
00472 };
00473
00474
00475
00476 static std::string
00477 kpse_var_value (const std::string& var)
00478 {
00479 std::string ret;
00480
00481 std::string tmp = octave_env::getenv (var);
00482
00483 if (! tmp.empty ())
00484 ret = kpse_var_expand (tmp);
00485
00486 #ifdef KPSE_DEBUG
00487 if (KPSE_DEBUG_P (KPSE_DEBUG_VARS))
00488 DEBUGF2 ("variable: %s = %s\n", var.c_str (),
00489 tmp.empty () ? "(nil)" : tmp.c_str ());
00490 #endif
00491
00492 return ret;
00493 }
00494
00495
00496
00497
00498 static std::string
00499 kpse_truncate_filename (const std::string& name)
00500 {
00501 unsigned c_len = 0;
00502 unsigned ret_len = 0;
00503
00504 std::string ret = name;
00505
00506 size_t len = name.length ();
00507
00508 for (size_t i = 0; i < len; i++)
00509 {
00510 if (IS_DIR_SEP (name[i]) || IS_DEVICE_SEP (name[i]))
00511 {
00512
00513 c_len = 0;
00514 }
00515 else if (c_len > NAME_MAX)
00516 {
00517
00518 continue;
00519 }
00520
00521
00522 ret[ret_len++] = name[i];
00523 c_len++;
00524 }
00525
00526 ret.resize (ret_len);
00527
00528 return ret;
00529 }
00530
00531
00532
00533
00534
00535
00536 #ifdef WIN32
00537 static inline bool
00538 READABLE (const std::string& fn, struct stat&)
00539 {
00540 const char *t = fn.c_str ();
00541 return (GetFileAttributes (t) != 0xFFFFFFFF
00542 && ! (GetFileAttributes (t) & FILE_ATTRIBUTE_DIRECTORY));
00543 }
00544 #else
00545 static inline bool
00546 READABLE (const std::string& fn, struct stat& st)
00547 {
00548 const char *t = fn.c_str ();
00549 return (access (t, R_OK) == 0
00550 && stat (t, &(st)) == 0 && ! S_ISDIR (st.st_mode));
00551 }
00552 #endif
00553
00554
00555
00556
00557
00558
00559
00560 static std::string
00561 kpse_readable_file (const std::string& name)
00562 {
00563 struct stat st;
00564 std::string ret;
00565
00566 if (READABLE (name, st))
00567 {
00568 ret = name;
00569
00570 #ifdef ENAMETOOLONG
00571 }
00572 else if (errno == ENAMETOOLONG)
00573 {
00574 ret = kpse_truncate_filename (name);
00575
00576
00577
00578
00579 if (! READABLE (ret, st))
00580 {
00581
00582 ret = std::string ();
00583 }
00584 #endif
00585
00586 }
00587 else
00588 {
00589
00590 if (errno == EACCES)
00591 {
00592
00593 perror (name.c_str ());
00594 }
00595
00596 ret = std::string ();
00597 }
00598
00599 return ret;
00600 }
00601
00602
00603
00604
00605 static bool
00606 kpse_absolute_p (const std::string& filename, int relative_ok)
00607 {
00608 size_t len = filename.length ();
00609
00610 int absolute = (len > 0 && IS_DIR_SEP (filename[0]))
00611 #ifdef DOSISH
00612
00613 || (len > 0 && IS_DEVICE_SEP (filename[1]))
00614 #endif
00615 #ifdef WIN32
00616
00617 || (len > 1 && filename[0] == '\\' && filename[1] == '\\')
00618 #endif
00619 ;
00620
00621 int explicit_relative
00622 = relative_ok
00623 && (len > 1
00624 && filename[0] == '.'
00625 && (IS_DIR_SEP (filename[1])
00626 || (len > 2 && filename[1] == '.' && IS_DIR_SEP (filename[2]))));
00627
00628 return absolute || explicit_relative;
00629 }
00630
00631
00632
00633
00634
00635
00636
00637 static bool first_search = true;
00638
00639
00640
00641
00642
00643 static void
00644 log_search (const string_vector& filenames)
00645 {
00646 static FILE *log_file = 0;
00647 static bool first_time = true;
00648
00649 if (first_time)
00650 {
00651 first_time = false;
00652
00653
00654 std::string log_name = kpse_var_value ("TEXMFLOG");
00655
00656 if (! log_name.empty ())
00657 {
00658 log_file = xfopen (log_name.c_str (), "a");
00659
00660 if (! log_file)
00661 perror (log_name.c_str ());
00662 }
00663 }
00664
00665 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH) || log_file)
00666 {
00667
00668 for (int e = 0; e < filenames.length () && ! filenames[e].empty (); e++)
00669 {
00670 std::string filename = filenames[e];
00671
00672
00673 if (log_file && kpse_absolute_p (filename.c_str (), false))
00674 fprintf (log_file, "%lu %s\n", (long unsigned) time (0),
00675 filename.c_str ());
00676
00677
00678
00679
00680 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00681 fputs (filename.c_str (), stderr);
00682 }
00683 }
00684 }
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 static string_vector
00697 dir_list_search (str_llist_type *dirs, const std::string& name,
00698 bool search_all)
00699 {
00700 str_llist_elt_type *elt;
00701 string_vector ret;
00702
00703 for (elt = *dirs; elt; elt = STR_LLIST_NEXT (*elt))
00704 {
00705 const std::string dir = STR_LLIST (*elt);
00706
00707 std::string potential = dir + name;
00708
00709 std::string tmp = kpse_readable_file (potential);
00710
00711 if (! tmp.empty ())
00712 {
00713 ret.append (potential);
00714
00715
00716 str_llist_float (dirs, elt);
00717
00718 if (! search_all)
00719 return ret;
00720 }
00721 }
00722
00723 return ret;
00724 }
00725
00726
00727
00728
00729 static string_vector
00730 absolute_search (const std::string& name)
00731 {
00732 string_vector ret_list;
00733 std::string found = kpse_readable_file (name);
00734
00735
00736
00737 ret_list.append (found);
00738
00739 return ret_list;
00740 }
00741
00742
00743
00744
00745 static string_vector
00746 path_search (const std::string& path, const std::string& name,
00747 bool , bool all)
00748 {
00749 string_vector ret_list;
00750 bool done = false;
00751
00752 for (kpse_path_iterator pi (path); ! done && pi != NPOS; pi++)
00753 {
00754 std::string elt = *pi;
00755
00756 string_vector found;
00757 bool allow_disk_search = true;
00758
00759 if (elt.length () > 1 && elt[0] == '!' && elt[1] == '!')
00760 {
00761
00762
00763
00764 allow_disk_search = false;
00765 elt = elt.substr (2);
00766 }
00767
00768
00769 if (NAME_BEGINS_WITH_DEVICE (elt))
00770 {
00771 while (elt.length () > 3
00772 && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
00773 {
00774 elt[2] = elt[1];
00775 elt[1] = elt[0];
00776 elt = elt.substr (1);
00777 }
00778 }
00779 else
00780 {
00781
00782 while (elt.length () > 1
00783 && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
00784 elt = elt.substr (1);
00785 }
00786
00787
00788
00789 found = first_search
00790 ? string_vector () : kpse_db_search (name, elt, all);
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800 if (allow_disk_search && found.empty ())
00801 {
00802 str_llist_type *dirs = kpse_element_dirs (elt);
00803
00804 if (dirs && *dirs)
00805 found = dir_list_search (dirs, name, all);
00806 }
00807
00808
00809 if (! found.empty ())
00810 {
00811 if (all)
00812 ret_list.append (found);
00813 else
00814 {
00815 ret_list.append (found[0]);
00816 done = true;
00817 }
00818 }
00819 }
00820
00821 return ret_list;
00822 }
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832 static string_vector
00833 search (const std::string& path, const std::string& original_name,
00834 bool must_exist, bool all)
00835 {
00836 string_vector ret_list;
00837 bool absolute_p;
00838
00839
00840 std::string name = kpse_expand (original_name);
00841
00842
00843
00844 absolute_p = kpse_absolute_p (name, true);
00845
00846 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00847 DEBUGF4 ("start search (file=%s, must_exist=%d, find_all=%d, path=%s).\n",
00848 name.c_str (), must_exist, all, path.c_str ());
00849
00850
00851 ret_list = absolute_p ? absolute_search (name)
00852 : path_search (path, name, must_exist, all);
00853
00854
00855
00856 if (first_search)
00857 {
00858 first_search = false;
00859 }
00860 else
00861 {
00862
00863
00864
00865 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00866 DEBUGF1 ("search (%s) =>", original_name.c_str ());
00867
00868 log_search (ret_list);
00869
00870 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00871 putc ('\n', stderr);
00872 }
00873
00874 return ret_list;
00875 }
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 static std::string
00898 kpse_path_search (const std::string& path, const std::string& name,
00899 bool must_exist)
00900 {
00901 string_vector ret_list = search (path, name, must_exist, false);
00902
00903 return ret_list.empty () ? std::string () : ret_list[0];
00904 }
00905
00906
00907
00908
00909
00910
00911
00912 static string_vector
00913 kpse_all_path_search (const std::string& path, const std::string& name)
00914 {
00915 return search (path, name, true, true);
00916 }
00917
00918
00919
00920
00921
00922 static string_vector
00923 path_find_first_of (const std::string& path, const string_vector& names,
00924 bool , bool all)
00925 {
00926 string_vector ret_list;
00927 bool done = false;
00928
00929 for (kpse_path_iterator pi (path); ! done && pi != NPOS; pi++)
00930 {
00931 std::string elt = *pi;
00932
00933 str_llist_type *dirs;
00934 str_llist_elt_type *dirs_elt;
00935 string_vector found;
00936 bool allow_disk_search = true;
00937
00938 if (elt.length () > 1 && elt[0] == '!' && elt[1] == '!')
00939 {
00940
00941
00942
00943
00944 allow_disk_search = false;
00945 elt = elt.substr (2);
00946 }
00947
00948
00949
00950 if (NAME_BEGINS_WITH_DEVICE (elt))
00951 {
00952 while (elt.length () > 3
00953 && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
00954 {
00955 elt[2] = elt[1];
00956 elt[1] = elt[0];
00957 elt = elt.substr (1);
00958 }
00959 }
00960 else
00961 {
00962
00963 while (elt.length () > 1
00964 && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
00965 elt = elt.substr (1);
00966 }
00967
00968
00969 dirs = kpse_element_dirs (elt);
00970 for (dirs_elt = *dirs; dirs_elt; dirs_elt = STR_LLIST_NEXT (*dirs_elt))
00971 {
00972 const std::string dir = STR_LLIST (*dirs_elt);
00973
00974 int len = names.length ();
00975 for (int i = 0; i < len && !done; i++)
00976 {
00977 std::string name = names[i];
00978
00979
00980
00981
00982 found = first_search
00983 ? string_vector () : kpse_db_search (name, dir.c_str (), all);
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 if (allow_disk_search && found.empty ())
00997 {
00998 static str_llist_type *tmp = 0;
00999
01000 if (! tmp)
01001 {
01002 tmp = new str_llist_type;
01003 *tmp = 0;
01004 str_llist_add (tmp, "");
01005 }
01006
01007 STR_LLIST (*(*tmp)) = dir;
01008
01009 found = dir_list_search (tmp, name, all);
01010 }
01011
01012
01013 if (! found.empty ())
01014 {
01015 if (all)
01016 ret_list.append (found);
01017 else
01018 {
01019 ret_list.append (found[0]);
01020 done = true;
01021 }
01022 }
01023 }
01024 }
01025 }
01026
01027 return ret_list;
01028 }
01029
01030 static string_vector
01031 find_first_of (const std::string& path, const string_vector& names,
01032 bool must_exist, bool all)
01033 {
01034 string_vector ret_list;
01035
01036 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01037 {
01038 fputs ("start find_first_of ((", stderr);
01039
01040 int len = names.length ();
01041
01042 for (int i = 0; i < len; i++)
01043 {
01044 if (i == 0)
01045 fputs (names[i].c_str (), stderr);
01046 else
01047 fprintf (stderr, ", %s", names[i].c_str ());
01048 }
01049
01050 fprintf (stderr, "), path=%s, must_exist=%d).\n",
01051 path.c_str (), must_exist);
01052 }
01053
01054 for (int i = 0; i < names.length (); i++)
01055 {
01056 std::string name = names[i];
01057
01058 if (kpse_absolute_p (name, true))
01059 {
01060
01061
01062
01063
01064 ret_list = absolute_search (name);
01065
01066 if (! ret_list.empty ())
01067 return ret_list;
01068 }
01069 }
01070
01071
01072 ret_list = path_find_first_of (path, names, must_exist, all);
01073
01074
01075
01076 if (first_search)
01077 {
01078 first_search = false;
01079 }
01080 else
01081 {
01082
01083
01084
01085 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01086 {
01087 fputs ("find_first_of (", stderr);
01088
01089 int len = names.length ();
01090
01091 for (int i = 0; i < len; i++)
01092 {
01093 if (i == 0)
01094 fputs (names[i].c_str (), stderr);
01095 else
01096 fprintf (stderr, ", %s", names[i].c_str ());
01097 }
01098 fputs (") =>", stderr);
01099 }
01100
01101 log_search (ret_list);
01102
01103 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01104 putc ('\n', stderr);
01105 }
01106
01107 return ret_list;
01108 }
01109
01110
01111
01112
01113
01114
01115
01116 static std::string
01117 kpse_path_find_first_of (const std::string& path, const string_vector& names,
01118 bool must_exist)
01119 {
01120 string_vector ret_list = find_first_of (path, names, must_exist, false);
01121
01122 return ret_list.empty () ? std::string () : ret_list[0];
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132 static string_vector
01133 kpse_all_path_find_first_of (const std::string& path,
01134 const string_vector& names)
01135 {
01136 return find_first_of (path, names, true, true);
01137 }
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148 static std::string
01149 kpse_tilde_expand (const std::string& name)
01150 {
01151 std::string expansion;
01152
01153 assert (! name.empty ());
01154
01155
01156 if (name[0] != '~')
01157 {
01158 expansion = name;
01159
01160
01161
01162
01163 }
01164 else if (name.length () == 1)
01165 {
01166 expansion = octave_env::getenv ("HOME");
01167
01168 if (expansion.empty ())
01169 expansion = ".";
01170
01171
01172
01173 }
01174 else if (IS_DIR_SEP (name[1]))
01175 {
01176 unsigned c = 1;
01177 std::string home = octave_env::getenv ("HOME");
01178
01179 if (home.empty ())
01180 home = ".";
01181
01182 size_t home_len = home.length ();
01183
01184
01185 if (home_len > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
01186 home = home.substr (1);
01187
01188
01189 if (IS_DIR_SEP (home[home_len - 1]))
01190 c++;
01191
01192 expansion = home + name.substr (c);
01193
01194
01195
01196 }
01197 else
01198 #ifdef HAVE_PWD_H
01199 {
01200 unsigned c = 2;
01201
01202
01203 while (name.length () > c && ! IS_DIR_SEP (name[c]))
01204 c++;
01205
01206 std::string user = name.substr (1, c-1);
01207
01208
01209
01210 octave_passwd p = octave_passwd::getpwnam (user);
01211
01212
01213 std::string home = p ? p.dir () : std::string (".");
01214
01215 if (home.empty ())
01216 home = ".";
01217
01218
01219 if (home.length () > 1 && IS_DIR_SEP (home[0]) && IS_DIR_SEP (home[1]))
01220 home = home.substr (1);
01221
01222
01223 if (name.length () > c && IS_DIR_SEP (home[home.length () - 1]))
01224 c++;
01225
01226 expansion = name.length () > c ? home : home + name.substr (c);
01227 }
01228 #else
01229 expansion = name;
01230 #endif
01231
01232 return expansion;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241 static std::string
01242 kpse_expand (const std::string& s)
01243 {
01244 std::string var_expansion = kpse_var_expand (s);
01245 return kpse_tilde_expand (var_expansion);
01246 }
01247
01248
01249 static string_vector brace_expand (const std::string&);
01250
01251
01252
01253
01254 static std::string
01255 kpse_expand_kpse_dot (const std::string& path)
01256 {
01257 std::string ret;
01258 std::string kpse_dot = octave_env::getenv ("KPSE_DOT");
01259
01260 if (kpse_dot.empty ())
01261 return path;
01262
01263 for (kpse_path_iterator pi (path); pi != NPOS; pi++)
01264 {
01265 std::string elt = *pi;
01266
01267
01268
01269
01270 size_t elt_len = elt.length ();
01271
01272 if (kpse_absolute_p (elt, false)
01273 || (elt_len > 1 && elt[0] == '!' && elt[1] == '!'))
01274 ret += elt + ENV_SEP_STRING;
01275 else if (elt_len == 1 && elt[0] == '.')
01276 ret += kpse_dot + ENV_SEP_STRING;
01277 else if (elt_len > 1 && elt[0] == '.' && IS_DIR_SEP (elt[1]))
01278 ret += kpse_dot + elt.substr (1) + ENV_SEP_STRING;
01279 else
01280 ret += kpse_dot + DIR_SEP_STRING + elt + ENV_SEP_STRING;
01281 }
01282
01283 int len = ret.length ();
01284 if (len > 0)
01285 ret.resize (len-1);
01286
01287 return ret;
01288 }
01289
01290
01291
01292
01293
01294
01295 static std::string
01296 kpse_brace_expand_element (const std::string& elt)
01297 {
01298 std::string ret;
01299
01300 string_vector expansions = brace_expand (elt);
01301
01302 for (int i = 0; i < expansions.length (); i++)
01303 {
01304
01305 std::string x = kpse_expand (expansions[i]);
01306
01307 if (x != expansions[i])
01308 {
01309
01310
01311
01312
01313 x = kpse_brace_expand_element (x);
01314 }
01315
01316 ret += x + ENV_SEP_STRING;
01317 }
01318
01319 ret.resize (ret.length () - 1);
01320
01321 return ret;
01322 }
01323
01324
01325
01326
01327
01328
01329
01330 static std::string
01331 kpse_brace_expand (const std::string& path)
01332 {
01333
01334
01335
01336
01337
01338
01339 std::string tmp = kpse_var_expand (path);
01340
01341 std::string ret;
01342
01343 for (kpse_path_iterator pi (tmp); pi != NPOS; pi++)
01344 {
01345 std::string elt = *pi;
01346
01347
01348 std::string expansion = kpse_brace_expand_element (elt);
01349 ret += expansion + ENV_SEP_STRING;
01350 }
01351
01352 size_t len = ret.length ();
01353 if (len > 0)
01354 ret.resize (len-1);
01355
01356 return kpse_expand_kpse_dot (ret);
01357 }
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 static std::string
01368 kpse_path_expand (const std::string& path)
01369 {
01370 std::string ret;
01371 unsigned len;
01372
01373 len = 0;
01374
01375
01376 std::string tmp = kpse_brace_expand (path);
01377
01378
01379 for (kpse_path_iterator pi (tmp); pi != NPOS; pi++)
01380 {
01381 std::string elt = *pi;
01382
01383 str_llist_type *dirs;
01384
01385
01386 if (elt.length () > 1 && elt[0] == '!' && elt[1] == '!')
01387 elt = elt.substr (2);
01388
01389
01390 if (NAME_BEGINS_WITH_DEVICE (elt))
01391 {
01392 while (elt.length () > 3
01393 && IS_DIR_SEP (elt[2]) && IS_DIR_SEP (elt[3]))
01394 {
01395 elt[2] = elt[1];
01396 elt[1] = elt[0];
01397 elt = elt.substr (1);
01398 }
01399 }
01400 else
01401 {
01402
01403 while (elt.length () > 1
01404 && IS_DIR_SEP (elt[0]) && IS_DIR_SEP (elt[1]))
01405 elt = elt.substr (1);
01406 }
01407
01408
01409
01410 dirs = kpse_element_dirs (elt);
01411
01412 if (dirs && *dirs)
01413 {
01414 str_llist_elt_type *dir;
01415
01416 for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir))
01417 {
01418 const std::string thedir = STR_LLIST (*dir);
01419 unsigned dirlen = thedir.length ();
01420
01421 ret += thedir;
01422 len += dirlen;
01423
01424
01425 if (dirlen == 1
01426 || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (thedir)
01427 && IS_DIR_SEP (thedir[2])))
01428 {
01429 ret += ENV_SEP_STRING;
01430 len++;
01431 }
01432
01433 ret[len-1] = ENV_SEP;
01434 }
01435 }
01436 }
01437
01438 if (len > 0)
01439 ret.resize (len-1);
01440
01441 return ret;
01442 }
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464 #define brace_whitespace(c) (! (c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 static string_vector
01481 array_concat (const string_vector& arr1, const string_vector& arr2)
01482 {
01483 string_vector result;
01484
01485 if (arr1.empty ())
01486 result = arr2;
01487 else if (arr2.empty ())
01488 result = arr1;
01489 else
01490 {
01491 int len1 = arr1.length ();
01492 int len2 = arr2.length ();
01493
01494 result = string_vector (len1 * len2);
01495
01496 int k = 0;
01497 for (int i = 0; i < len2; i++)
01498 for (int j = 0; j < len1; j++)
01499 result[k++] = arr1[j] + arr2[i];
01500 }
01501
01502 return result;
01503 }
01504
01505 static int brace_gobbler (const std::string&, int&, int);
01506 static string_vector expand_amble (const std::string&);
01507
01508
01509 static string_vector
01510 brace_expand (const std::string& text)
01511 {
01512
01513 int i = 0;
01514 int c = brace_gobbler (text, i, '{');
01515
01516 std::string preamble = text.substr (0, i);
01517
01518 string_vector result = string_vector (preamble);
01519
01520 if (c == '{')
01521 {
01522
01523 int start = ++i;
01524 c = brace_gobbler (text, i, '}');
01525
01526
01527 if (! c)
01528 {
01529 (*current_liboctave_warning_handler)
01530 ("%s: Unmatched {", text.c_str ());
01531
01532 result = string_vector (text);
01533 }
01534 else
01535 {
01536 std::string amble = text.substr (start, i-start);
01537 result = array_concat (result, expand_amble (amble));
01538
01539 std::string postamble = text.substr (i+1);
01540 result = array_concat (result, brace_expand (postamble));
01541 }
01542 }
01543
01544 return result;
01545 }
01546
01547
01548 static int brace_arg_separator = ',';
01549
01550
01551
01552
01553
01554 static string_vector
01555 expand_amble (const std::string& text)
01556 {
01557 string_vector result;
01558
01559 size_t text_len = text.length ();
01560 size_t start;
01561 int i, c;
01562
01563 for (start = 0, i = 0, c = 1; c && start < text_len; start = ++i)
01564 {
01565 int i0 = i;
01566 int c0 = brace_gobbler (text, i0, brace_arg_separator);
01567 int i1 = i;
01568 int c1 = brace_gobbler (text, i1, ENV_SEP);
01569 c = c0 | c1;
01570 i = (i0 < i1 ? i0 : i1);
01571
01572 std::string tem = text.substr (start, i-start);
01573
01574 string_vector partial = brace_expand (tem);
01575
01576 if (result.empty ())
01577 result = partial;
01578 else
01579 result.append (partial);
01580 }
01581
01582 return result;
01583 }
01584
01585
01586
01587
01588
01589 static int
01590 brace_gobbler (const std::string& text, int& indx, int satisfy)
01591 {
01592 int c = 0, level = 0, quoted = 0, pass_next = 0;
01593
01594 size_t text_len = text.length ();
01595
01596 size_t i = indx;
01597
01598 for (; i < text_len; i++)
01599 {
01600 c = text[i];
01601
01602 if (pass_next)
01603 {
01604 pass_next = 0;
01605 continue;
01606 }
01607
01608
01609
01610 if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
01611 {
01612 pass_next = 1;
01613 continue;
01614 }
01615
01616 if (quoted)
01617 {
01618 if (c == quoted)
01619 quoted = 0;
01620 continue;
01621 }
01622
01623 if (c == '"' || c == '\'' || c == '`')
01624 {
01625 quoted = c;
01626 continue;
01627 }
01628
01629 if (c == satisfy && !level && !quoted)
01630 {
01631
01632
01633
01634 if (c == '{' &&
01635 ((i == 0 || brace_whitespace (text[i-1])) &&
01636 (i+1 < text_len &&
01637 (brace_whitespace (text[i+1]) || text[i+1] == '}'))))
01638 continue;
01639
01640
01641 if ((c != '{') || i == 0 || (text[i-1] != '$'))
01642 break;
01643 }
01644
01645 if (c == '{')
01646 level++;
01647 else if (c == '}' && level)
01648 level--;
01649 }
01650
01651 indx = i;
01652 return c;
01653 }
01654
01655
01656
01657
01658
01659
01660
01661
01662 struct kpse_format_info_type
01663 {
01664 std::string type;
01665 std::string path;
01666 std::string raw_path;
01667 std::string path_source;
01668 std::string override_path;
01669 std::string client_path;
01670 std::string cnf_path;
01671 std::string default_path;
01672 string_vector suffix;
01673 };
01674
01675
01676
01677 static kpse_format_info_type kpse_format_info;
01678
01679
01680
01681 #define EXPAND_DEFAULT(try_path, source_string) \
01682 do \
01683 { \
01684 if (! try_path.empty ()) \
01685 { \
01686 info.raw_path = try_path; \
01687 info.path = kpse_expand_default (try_path, info.path); \
01688 info.path_source = source_string; \
01689 } \
01690 } \
01691 while (0)
01692
01693 static hash_table_type db;
01694
01695 static hash_table_type alias_db;
01696
01697 static string_vector db_dir_list;
01698
01699
01700
01701
01702
01703 static bool
01704 match (const std::string& filename_arg, const std::string& path_elt_arg)
01705 {
01706 const char *filename = filename_arg.c_str ();
01707 const char *path_elt = path_elt_arg.c_str ();
01708
01709 const char *original_filename = filename;
01710 bool matched = false;
01711
01712 for (; *filename && *path_elt; filename++, path_elt++)
01713 {
01714 if (*filename == *path_elt)
01715 ;
01716
01717 else if (IS_DIR_SEP (*path_elt)
01718 && original_filename < filename && IS_DIR_SEP (path_elt[-1]))
01719 {
01720 while (IS_DIR_SEP (*path_elt))
01721 path_elt++;
01722
01723 if (*path_elt == 0)
01724 {
01725
01726
01727
01728 matched = true;
01729 break;
01730 }
01731 else
01732 {
01733
01734 for (; !matched && *filename; filename++)
01735 {
01736
01737 if (IS_DIR_SEP (filename[-1]) && *filename == *path_elt)
01738 matched = match (filename, path_elt);
01739 }
01740
01741
01742 break;
01743 }
01744 }
01745 else
01746
01747 break;
01748 }
01749
01750
01751
01752 if (! matched && *path_elt == 0)
01753 {
01754
01755
01756
01757
01758
01759
01760
01761
01762 if (IS_DIR_SEP (*filename))
01763 filename++;
01764
01765 while (*filename && !IS_DIR_SEP (*filename))
01766 filename++;
01767
01768 matched = *filename == 0;
01769 }
01770
01771 return matched;
01772 }
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784 static bool
01785 elt_in_db (const std::string& db_dir, const std::string& path_elt)
01786 {
01787 bool found = false;
01788
01789 size_t db_dir_len = db_dir.length ();
01790 size_t path_elt_len = path_elt.length ();
01791
01792 size_t i = 0;
01793
01794 while (! found && db_dir[i] == path_elt[i])
01795 {
01796 i++;
01797
01798 if (i == db_dir_len)
01799 found = true;
01800
01801
01802
01803 else if (i == path_elt_len)
01804 break;
01805 }
01806
01807 return found;
01808 }
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818 static string_vector
01819 kpse_db_search (const std::string& name_arg,
01820 const std::string& orig_path_elt, bool all)
01821 {
01822 bool done;
01823 string_vector ret;
01824 string_vector aliases;
01825 bool relevant = false;
01826
01827 std::string name = name_arg;
01828
01829
01830
01831 if (! db.buckets)
01832 return ret;
01833
01834
01835
01836
01837
01838
01839
01840 std::string path_elt;
01841 size_t last_slash = name.rfind ('/');
01842 if (last_slash != NPOS && last_slash != 0)
01843 {
01844 std::string dir_part = name.substr (0, last_slash);
01845 name = name.substr (last_slash + 1);
01846 }
01847 else
01848 path_elt = orig_path_elt;
01849
01850
01851
01852
01853
01854
01855 for (int e = 0; ! relevant && e < db_dir_list.length (); e++)
01856 relevant = elt_in_db (db_dir_list[e], path_elt);
01857
01858 if (! relevant)
01859 return ret;
01860
01861
01862 if (alias_db.buckets)
01863 aliases = hash_lookup (alias_db, name);
01864
01865
01866 int len = aliases.length ();
01867 aliases.resize (len+1);
01868 for (int i = len; i > 0; i--)
01869 aliases[i] = aliases[i - 1];
01870 aliases[0] = name;
01871
01872 done = false;
01873 len = aliases.length ();
01874 for (int i = 0; i < len && !done; i++)
01875 {
01876 std::string atry = aliases[i];
01877
01878
01879 string_vector db_dirs = hash_lookup (db, atry);
01880
01881
01882
01883
01884
01885 int db_dirs_len = db_dirs.length ();
01886 for (int j = 0; j < db_dirs_len && !done; j++)
01887 {
01888 std::string db_file = db_dirs[j] + atry;
01889 bool matched = match (db_file, path_elt);
01890
01891 #ifdef KPSE_DEBUG
01892 if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
01893 DEBUGF3 ("db:match (%s,%s) = %d\n", db_file.c_str (), path_elt.c_str (), matched);
01894 #endif
01895
01896
01897
01898 if (matched)
01899 {
01900 std::string found;
01901 std::string tmp = kpse_readable_file (db_file);
01902 if (! tmp.empty ())
01903 found = db_file;
01904 else
01905 {
01906
01907
01908
01909
01910
01911
01912
01913
01914 int aliases_len = aliases.length ();
01915
01916 for (int k = 1; k < aliases_len && found.empty (); k++)
01917 {
01918 std::string aatry = db_dirs[j] + aliases[k];
01919 tmp = kpse_readable_file (aatry);
01920 if (! tmp.empty ())
01921 found = aatry;
01922 }
01923 }
01924
01925
01926 if (! found.empty ())
01927 {
01928 ret.append (found);
01929
01930 if (! (all || found.empty ()))
01931 done = true;
01932 }
01933 }
01934 }
01935 }
01936
01937 return ret;
01938 }
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949 static std::string
01950 kpse_expand_default (const std::string& path, const std::string& fallback)
01951 {
01952 std::string expansion;
01953
01954 size_t path_len = path.length ();
01955
01956 if (path_len == 0)
01957 expansion = fallback;
01958
01959
01960 else if (IS_ENV_SEP (path[0]))
01961 {
01962 expansion = path_len == 1 ? fallback : fallback + path;
01963 }
01964
01965
01966
01967
01968
01969
01970 else if (IS_ENV_SEP (path[path_len-1]))
01971 expansion = path + fallback;
01972
01973
01974 else
01975 {
01976
01977 expansion = path;
01978
01979 for (size_t i = 0; i < path_len; i++)
01980 {
01981 if (i + 1 < path_len
01982 && IS_ENV_SEP (path[i]) && IS_ENV_SEP (path[i+1]))
01983 {
01984
01985
01986
01987
01988 expansion = path.substr (0, i+1) + fallback + path.substr (i+1);
01989
01990 break;
01991 }
01992 }
01993 }
01994
01995 return expansion;
01996 }
01997
01998
01999
02000
02001
02002
02003
02004
02005
02006
02007 static void
02008 dir_list_add (str_llist_type *l, const std::string& dir)
02009 {
02010 char last_char = dir[dir.length () - 1];
02011
02012 std::string saved_dir = dir;
02013
02014 if (! (IS_DIR_SEP (last_char) || IS_DEVICE_SEP (last_char)))
02015 saved_dir += DIR_SEP_STRING;
02016
02017 str_llist_add (l, saved_dir);
02018 }
02019
02020
02021
02022
02023 static bool
02024 dir_p (const std::string& fn)
02025 {
02026 #ifdef WIN32
02027 unsigned int fa = GetFileAttributes (fn.c_str ());
02028 return (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
02029 #else
02030 struct stat stats;
02031 return stat (fn.c_str (), &stats) == 0 && S_ISDIR (stats.st_mode);
02032 #endif
02033 }
02034
02035
02036
02037 static void
02038 checked_dir_list_add (str_llist_type *l, const std::string& dir)
02039 {
02040 if (dir_p (dir))
02041 dir_list_add (l, dir);
02042 }
02043
02044
02045
02046
02047
02048
02049
02050 struct cache_entry
02051 {
02052 std::string key;
02053 str_llist_type *value;
02054 };
02055
02056 static cache_entry *the_cache = 0;
02057 static unsigned cache_length = 0;
02058
02059
02060
02061
02062
02063
02064
02065 static void
02066 cache (const std::string key, str_llist_type *value)
02067 {
02068 cache_entry *new_cache = new cache_entry [cache_length+1];
02069
02070 for (unsigned i = 0; i < cache_length; i++)
02071 {
02072 new_cache[i].key = the_cache[i].key;
02073 new_cache[i].value = the_cache[i].value;
02074 }
02075
02076 delete [] the_cache;
02077
02078 the_cache = new_cache;
02079
02080 the_cache[cache_length].key = key;
02081 the_cache[cache_length].value = value;
02082
02083 cache_length++;
02084 }
02085
02086
02087
02088 static str_llist_type *
02089 cached (const std::string& key)
02090 {
02091 unsigned p;
02092
02093 for (p = 0; p < cache_length; p++)
02094 {
02095 if (key == the_cache[p].key)
02096 return the_cache[p].value;
02097 }
02098
02099 return 0;
02100 }
02101
02102
02103
02104
02105 static void expand_elt (str_llist_type *, const std::string&, unsigned);
02106
02107
02108
02109
02110
02111
02112 #ifdef WIN32
02113
02114
02115 static std::string dirname;
02116
02117 #else
02118
02119
02120
02121
02122
02123 static int
02124 dir_links (const std::string& fn)
02125 {
02126 std::map<std::string, long> link_table;
02127
02128 long ret;
02129
02130 if (link_table.find (fn) != link_table.end ())
02131 ret = link_table[fn];
02132 else
02133 {
02134 struct stat stats;
02135
02136 ret = stat (fn.c_str (), &stats) == 0 && S_ISDIR (stats.st_mode)
02137 ? stats.st_nlink : (unsigned) -1;
02138
02139 link_table[fn] = ret;
02140
02141 #ifdef KPSE_DEBUG
02142 if (KPSE_DEBUG_P (KPSE_DEBUG_STAT))
02143 DEBUGF2 ("dir_links (%s) => %ld\n", fn.c_str (), ret);
02144 #endif
02145 }
02146
02147 return ret;
02148 }
02149
02150 #endif
02151
02152 static void
02153 do_subdir (str_llist_type *str_list_ptr, const std::string& elt,
02154 unsigned elt_length, const std::string& post)
02155 {
02156 #ifdef WIN32
02157 WIN32_FIND_DATA find_file_data;
02158 HANDLE hnd;
02159 int proceed;
02160 #else
02161 DIR *dir;
02162 struct dirent *e;
02163 #endif
02164
02165 std::string name = elt.substr (0, elt_length);
02166
02167 assert (IS_DIR_SEP (elt[elt_length - 1])
02168 || IS_DEVICE_SEP (elt[elt_length - 1]));
02169
02170 #if defined (WIN32)
02171
02172 dirname = name + "/*.*";
02173
02174 hnd = FindFirstFile (dirname.c_str (), &find_file_data);
02175
02176 if (hnd == INVALID_HANDLE_VALUE)
02177 return;
02178
02179
02180 if (post.empty ())
02181 dir_list_add (str_list_ptr, name);
02182 else
02183 {
02184
02185
02186
02187 name += post;
02188 expand_elt (str_list_ptr, name, elt_length);
02189 name.resize (elt_length);
02190 }
02191
02192 proceed = 1;
02193
02194 while (proceed)
02195 {
02196 if (find_file_data.cFileName[0] != '.')
02197 {
02198
02199 name += find_file_data.cFileName;
02200
02201 if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
02202 {
02203
02204 name += DIR_SEP_STRING;
02205 unsigned potential_len = name.length ();
02206
02207 do_subdir (str_list_ptr, name, potential_len, post);
02208 }
02209 name.resize (elt_length);
02210 }
02211
02212 proceed = FindNextFile (hnd, &find_file_data);
02213 }
02214
02215 FindClose (hnd);
02216
02217 #else
02218
02219
02220 dir = opendir (name.c_str ());
02221
02222 if (! dir)
02223 return;
02224
02225
02226 if (post.empty ())
02227 dir_list_add (str_list_ptr, name);
02228 else
02229 {
02230
02231
02232
02233 name += post;
02234 expand_elt (str_list_ptr, name, elt_length);
02235 name.resize (elt_length);
02236 }
02237
02238 while ((e = readdir (dir)))
02239 {
02240
02241
02242
02243 if (e->d_name[0] != '.')
02244 {
02245 int links;
02246
02247
02248 name += e->d_name;
02249
02250
02251 links = dir_links (name);
02252
02253 if (links >= 0)
02254 {
02255
02256 name += DIR_SEP_STRING;
02257 unsigned potential_len = name.length ();
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270 #ifdef ST_NLINK_TRICK
02271 if (links > 2)
02272 #endif
02273
02274 do_subdir (str_list_ptr, name, potential_len, post);
02275 #ifdef ST_NLINK_TRICK
02276 else if (post.empty ())
02277
02278
02279 dir_list_add (str_list_ptr, name);
02280 #endif
02281 }
02282
02283
02284 name.resize (elt_length);
02285 }
02286 }
02287
02288 xclosedir (dir);
02289 #endif
02290 }
02291
02292
02293
02294
02295
02296 static void
02297 expand_elt (str_llist_type *str_list_ptr, const std::string& elt,
02298 unsigned start)
02299 {
02300 size_t elt_len = elt.length ();
02301
02302 size_t dir = start;
02303
02304
02305 while (dir < elt_len)
02306 {
02307 if (IS_DIR_SEP (elt[dir]))
02308 {
02309
02310 if (++dir < elt_len && IS_DIR_SEP (elt[dir]))
02311 {
02312 size_t i = dir;
02313 while (i < elt_len && IS_DIR_SEP (elt[i]))
02314 i++;
02315
02316 std::string post = elt.substr (i);
02317
02318 do_subdir (str_list_ptr, elt, dir, post);
02319
02320 return;
02321 }
02322
02323
02324 }
02325 else
02326 dir++;
02327 }
02328
02329
02330 checked_dir_list_add (str_list_ptr, elt);
02331 }
02332
02333
02334
02335
02336
02337
02338
02339
02340
02341
02342
02343
02344 static str_llist_type *
02345 kpse_element_dirs (const std::string& elt)
02346 {
02347 str_llist_type *ret;
02348
02349
02350 if (elt.empty ())
02351 return 0;
02352
02353
02354 ret = cached (elt);
02355 if (ret)
02356 return ret;
02357
02358
02359 ret = new str_llist_type;
02360 *ret = 0;
02361
02362
02363 expand_elt (ret, elt, 0);
02364
02365
02366
02367 cache (elt, ret);
02368
02369 #ifdef KPSE_DEBUG
02370 if (KPSE_DEBUG_P (KPSE_DEBUG_EXPAND))
02371 {
02372 DEBUGF1 ("path element %s =>", elt.c_str ());
02373 if (ret)
02374 {
02375 str_llist_elt_type *e;
02376 for (e = *ret; e; e = STR_LLIST_NEXT (*e))
02377 fprintf (stderr, " %s", (STR_LLIST (*e)).c_str ());
02378 }
02379 putc ('\n', stderr);
02380 fflush (stderr);
02381 }
02382 #endif
02383
02384 return ret;
02385 }
02386
02387 #ifndef WIN32
02388 void
02389 xclosedir (DIR *d)
02390 {
02391 #ifdef CLOSEDIR_VOID
02392 closedir (d);
02393 #else
02394 int ret = closedir (d);
02395
02396 if (ret != 0)
02397 FATAL ("closedir failed");
02398 #endif
02399 }
02400 #endif
02401
02402
02403
02404 #ifdef KPSE_DEBUG
02405
02406
02407
02408
02409 static FILE *
02410 fopen (const char *filename, const char *mode)
02411 {
02412 #undef fopen
02413 FILE *ret = fopen (filename, mode);
02414
02415 if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN))
02416 DEBUGF3 ("fopen (%s, %s) => 0x%lx\n", filename, mode, (unsigned long) ret);
02417
02418 return ret;
02419 }
02420
02421 #endif
02422
02423
02424
02425
02426
02427 static void
02428 str_llist_add (str_llist_type *l, const std::string& str)
02429 {
02430 str_llist_elt_type *e;
02431 str_llist_elt_type *new_elt = new str_llist_elt_type;
02432
02433
02434 STR_LLIST (*new_elt) = str;
02435 STR_LLIST_MOVED (*new_elt) = 0;
02436 STR_LLIST_NEXT (*new_elt) = 0;
02437
02438
02439 for (e = *l; e && STR_LLIST_NEXT (*e); e = STR_LLIST_NEXT (*e))
02440 ;
02441
02442 if (! e)
02443 *l = new_elt;
02444 else
02445 STR_LLIST_NEXT (*e) = new_elt;
02446 }
02447
02448
02449
02450
02451
02452
02453 static void
02454 str_llist_float (str_llist_type *l, str_llist_elt_type *mover)
02455 {
02456 str_llist_elt_type *last_moved, *unmoved;
02457
02458
02459 if (STR_LLIST_MOVED (*mover))
02460 return;
02461
02462
02463
02464
02465 for (last_moved = 0, unmoved = *l; STR_LLIST_MOVED (*unmoved);
02466 last_moved = unmoved, unmoved = STR_LLIST_NEXT (*unmoved))
02467 ;
02468
02469
02470 if (unmoved != mover)
02471 {
02472
02473 str_llist_elt_type *before_mover;
02474 str_llist_elt_type *after_mover = STR_LLIST_NEXT (*mover);
02475
02476
02477 for (before_mover = unmoved; STR_LLIST_NEXT (*before_mover) != mover;
02478 before_mover = STR_LLIST_NEXT (*before_mover))
02479 ;
02480
02481
02482 STR_LLIST_NEXT (*before_mover) = after_mover;
02483
02484
02485
02486 STR_LLIST_NEXT (*mover) = unmoved;
02487 if (! last_moved)
02488 *l = mover;
02489 else
02490 STR_LLIST_NEXT (*last_moved) = mover;
02491 }
02492
02493
02494 STR_LLIST_MOVED (*mover) = 1;
02495 }
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505 static std::map <std::string, bool> expansions;
02506
02507 static void
02508 expanding (const std::string& var, bool xp)
02509 {
02510 expansions[var] = xp;
02511 }
02512
02513
02514
02515 static bool
02516 expanding_p (const std::string& var)
02517 {
02518 return (expansions.find (var) != expansions.end ())
02519 ? expansions[var] : false;
02520 }
02521
02522
02523
02524
02525
02526 static void
02527 expand (std::string &expansion, const std::string& var)
02528 {
02529 if (expanding_p (var))
02530 {
02531 (*current_liboctave_warning_handler)
02532 ("kpathsea: variable `%s' references itself (eventually)",
02533 var.c_str ());
02534 }
02535 else
02536 {
02537
02538 std::string value = octave_env::getenv (var);
02539
02540 if (! value.empty ())
02541 {
02542 expanding (var, true);
02543 std::string tmp = kpse_var_expand (value);
02544 expanding (var, false);
02545 expansion += tmp;
02546 }
02547 }
02548 }
02549
02550
02551
02552 #ifndef IS_VAR_START
02553 #define IS_VAR_START(c) ((c) == '$')
02554 #endif
02555 #ifndef IS_VAR_CHAR
02556 #define IS_VAR_CHAR(c) (isalnum (c) || (c) == '_')
02557 #endif
02558 #ifndef IS_VAR_BEGIN_DELIMITER
02559 #define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
02560 #endif
02561 #ifndef IS_VAR_END_DELIMITER
02562 #define IS_VAR_END_DELIMITER(c) ((c) == '}')
02563 #endif
02564
02565
02566
02567
02568 static std::string
02569 kpse_var_expand (const std::string& src)
02570 {
02571 std::string expansion;
02572
02573 size_t src_len = src.length ();
02574
02575
02576 for (size_t i = 0; i < src_len; i++)
02577 {
02578 if (IS_VAR_START (src[i]))
02579 {
02580 i++;
02581
02582
02583 if (IS_VAR_CHAR (src[i]))
02584 {
02585
02586 size_t var_end = i;
02587
02588 do
02589 {
02590 var_end++;
02591 }
02592 while (IS_VAR_CHAR (src[var_end]));
02593
02594 var_end--;
02595 expand (expansion, src.substr (i, var_end - i + 1));
02596 i = var_end;
02597
02598 }
02599 else if (IS_VAR_BEGIN_DELIMITER (src[i]))
02600 {
02601
02602 size_t var_end = ++i;
02603
02604 while (var_end < src_len && !IS_VAR_END_DELIMITER (src[var_end]))
02605 var_end++;
02606
02607 if (var_end == src_len)
02608 {
02609 (*current_liboctave_warning_handler)
02610 ("%s: No matching } for ${", src.c_str ());
02611 i = var_end - 1;
02612 }
02613 else
02614 {
02615 expand (expansion, src.substr (i, var_end - i));
02616 i = var_end;
02617 }
02618 }
02619 else
02620 {
02621
02622 (*current_liboctave_warning_handler)
02623 ("%s: Unrecognized variable construct `$%c'",
02624 src.c_str (), src[i]);
02625
02626
02627 }
02628 }
02629 else
02630 expansion += src[i];
02631 }
02632
02633 return expansion;
02634 }
02635
02636
02637
02638
02639
02640