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