~ubuntu-branches/ubuntu/quantal/ruby1.9.1/quantal

« back to all changes in this revision

Viewing changes to dln.c

  • Committer: Bazaar Package Importer
  • Author(s): Lucas Nussbaum
  • Date: 2010-07-31 17:08:39 UTC
  • mfrom: (1.1.4 upstream) (8.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100731170839-j034dmpdqt1cc4p6
Tags: 1.9.2~svn28788-1
* New release based on upstream snapshot from the 1.9.2 branch,
  after 1.9.2 RC2. That branch is (supposed to be) binary-compatible
  with the 1.9.1 branch.
  + Builds fine on i386. Closes: #580852.
* Upgrade to Standards-Version: 3.9.1. No changes needed.
* Updated generated incs.
* Patches that still need work:
  + Unclear status, need more investigation:
   090729_fix_Makefile_deps.dpatch
   090803_exclude_rdoc.dpatch
   203_adjust_base_of_search_path.dpatch
   902_define_YAML_in_yaml_stringio.rb.dpatch
   919_common.mk_tweaks.dpatch
   931_libruby_suffix.dpatch
   940_test_thread_mutex_sync_shorter.dpatch
  + Maybe not needed anymore, keeping but not applying.
   102_skip_test_copy_stream.dpatch (test doesn't block anymore?)
   104_skip_btest_io.dpatch (test doesn't block anymore?)
   201_gem_prelude.dpatch (we don't use that rubygems anyway?)
   202_gem_default_dir.dpatch (we don't use that rubygems anyway?)
   940_test_file_exhaustive_fails_as_root.dpatch
   940_test_priority_fails.dpatch
   100518_load_libc_libm.dpatch
* Add disable-tests.diff: disable some tests that cause failures on FreeBSD.
  Closes: #590002, #543805, #542927.
* However, many new failures on FreeBSD. Since that version is still an
  improvement, add the check that makes test suite failures non-fatal on
  FreeBSD again. That still needs to be investigated.
* Re-add 903_skip_base_ruby_check.dpatch
* Add build-dependency on ruby1.8 and drop all pre-generated files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
 
10
10
**********************************************************************/
11
11
 
 
12
#ifdef RUBY_EXPORT
12
13
#include "ruby/ruby.h"
 
14
#define dln_notimplement rb_notimplement
 
15
#define dln_memerror rb_memerror
 
16
#define dln_exit rb_exit
 
17
#define dln_loaderror rb_loaderror
 
18
#else
 
19
#define dln_notimplement --->>> dln not implemented <<<---
 
20
#define dln_memerror abort
 
21
#define dln_exit exit
 
22
static void dln_loaderror(const char *format, ...);
 
23
#endif
13
24
#include "dln.h"
14
25
 
15
26
#ifdef HAVE_STDLIB_H
16
27
# include <stdlib.h>
17
28
#endif
18
29
 
19
 
#ifdef __CHECKER__
20
 
#undef HAVE_DLOPEN
21
 
#undef USE_DLN_A_OUT
22
 
#undef USE_DLN_DLOPEN
23
 
#endif
24
 
 
25
30
#ifdef USE_DLN_A_OUT
26
31
char *dln_argv0;
27
32
#endif
79
84
# endif
80
85
#endif
81
86
 
82
 
#ifdef __BEOS__
 
87
#if defined(__BEOS__) || defined(__HAIKU__)
83
88
# include <image.h>
84
89
#endif
85
90
 
86
 
#ifndef NO_DLN_LOAD
 
91
#ifndef dln_loaderror
 
92
static void
 
93
dln_loaderror(const char *format, ...)
 
94
{
 
95
    va_list ap;
 
96
    va_start(ap, format);
 
97
    vfprintf(stderr, format, ap);
 
98
    va_end(ap);
 
99
    abort();
 
100
}
 
101
#endif
87
102
 
88
103
#if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
89
104
/* dynamic load with dlopen() */
91
106
#endif
92
107
 
93
108
#ifndef FUNCNAME_PATTERN
94
 
# if defined(__hp9000s300) ||  (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
 
109
# if defined(__hp9000s300) || ((defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && !defined(__ELF__)) || defined(__BORLANDC__) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
95
110
#  define FUNCNAME_PATTERN "_Init_%s"
96
111
# else
97
112
#  define FUNCNAME_PATTERN "Init_%s"
98
113
# endif
99
114
#endif
100
115
 
101
 
static int
 
116
static size_t
102
117
init_funcname_len(char **buf, const char *file)
103
118
{
104
119
    char *p;
105
120
    const char *slash;
106
 
    int len;
 
121
    size_t len;
107
122
 
108
123
    /* Load the file as an object one */
109
124
    for (slash = file-1; *file; file++) /* Find position of last '/' */
121
136
}
122
137
 
123
138
#define init_funcname(buf, file) do {\
124
 
    int len = init_funcname_len(buf, file);\
 
139
    size_t len = init_funcname_len(buf, file);\
125
140
    char *tmp = ALLOCA_N(char, len+1);\
126
141
    if (!tmp) {\
127
142
        free(*buf);\
128
 
        rb_memerror();\
 
143
        dln_memerror();\
129
144
    }\
130
 
    strcpy(tmp, *buf);\
 
145
    strlcpy(tmp, *buf, len + 1);\
131
146
    free(*buf);\
132
147
    *buf = tmp;\
133
148
} while (0)
445
460
}
446
461
 
447
462
static void
448
 
dln_print_undef()
 
463
dln_print_undef(void)
449
464
{
450
465
    fprintf(stderr, " Undefined symbols:\n");
451
466
    st_foreach(undef_tbl, undef_print, NULL);
452
467
}
453
468
 
454
469
static void
455
 
dln_undefined()
 
470
dln_undefined(void)
456
471
{
457
472
    if (undef_tbl->num_entries > 0) {
458
473
        fprintf(stderr, "dln: Calling undefined function\n");
459
474
        dln_print_undef();
460
 
        rb_exit(1);
 
475
        dln_exit(1);
461
476
    }
462
477
}
463
478
 
766
781
                }
767
782
            } /* end.. look it up */
768
783
            else { /* is static */
769
 
                switch (R_SYMBOL(rel)) { 
 
784
                switch (R_SYMBOL(rel)) {
770
785
                  case N_TEXT:
771
786
                  case N_DATA:
772
787
                    datum = block;
890
905
    int lib_offset;
891
906
};
892
907
 
893
 
char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
 
908
const char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
894
909
 
895
910
static int
896
911
load_lib(const char *lib)
897
912
{
898
913
    char *path, *file, fbuf[MAXPATHLEN];
 
914
    char *envpath = 0;
899
915
    char armagic[SARMAG];
900
916
    int fd, size;
901
917
    struct ar_hdr ahdr;
925
941
    /* if path is still NULL, use "." for path. */
926
942
    path = getenv("DLN_LIBRARY_PATH");
927
943
    if (path == NULL) path = dln_librrb_ary_path;
 
944
    else path = envpath = strdup(path);
928
945
 
929
946
    file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf));
 
947
    if (envpath) free(envpath);
930
948
    fd = open(file, O_RDONLY);
931
949
    if (fd == -1) goto syserr;
932
950
    size = read(fd, armagic, SARMAG);
1156
1174
static void
1157
1175
aix_loaderror(const char *pathname)
1158
1176
{
1159
 
    char *message[1024], errbuf[1024];
1160
 
    int i,j;
1161
 
 
1162
 
    static const struct errtab {
1163
 
        int errnum;
1164
 
        const char * errstr;
1165
 
    } load_errtab[] = {
1166
 
        {L_ERROR_TOOMANY,       "too many errors, rest skipped."},
1167
 
        {L_ERROR_NOLIB,         "can't load library:"},
1168
 
        {L_ERROR_UNDEF,         "can't find symbol in library:"},
1169
 
        {L_ERROR_RLDBAD,
1170
 
             "RLD index out of range or bad relocation type:"},
1171
 
        {L_ERROR_FORMAT,        "not a valid, executable xcoff file:"},
1172
 
        {L_ERROR_MEMBER,
1173
 
             "file not an archive or does not contain requested member:"},
1174
 
        {L_ERROR_TYPE,          "symbol table mismatch:"},
1175
 
        {L_ERROR_ALIGN,         "text alignment in file is wrong."},
1176
 
        {L_ERROR_SYSTEM,        "System error:"},
1177
 
        {L_ERROR_ERRNO,         NULL}
1178
 
    };
1179
 
 
1180
 
#define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
 
1177
  char *message[1024], errbuf[1024];
 
1178
  int i;
1181
1179
#define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
1182
 
 
1183
 
    snprintf(errbuf, sizeof(errbuf), "load failed - %s ", pathname);
1184
 
 
1185
 
    message[0] = NULL;
1186
 
    if (!loadquery(L_GETMESSAGES, &message[0], sizeof(message)))
1187
 
        ERRBUF_APPEND(strerror(errno));
1188
 
    for(i = 0; message[i] && *message[i]; i++) {
1189
 
        int nerr = atoi(message[i]);
1190
 
        for (j=0; j<LOAD_ERRTAB_LEN; j++) {
1191
 
           if (nerr == load_errtab[j].errnum && load_errtab[j].errstr)
1192
 
                ERRBUF_APPEND(load_errtab[j].errstr);
1193
 
        }
1194
 
        while (isdigit(*message[i])) message[i]++; 
1195
 
        ERRBUF_APPEND(message[i]);
1196
 
        ERRBUF_APPEND("\n");
 
1180
  snprintf(errbuf, sizeof(errbuf), "load failed - %s. ", pathname);
 
1181
 
 
1182
  if (loadquery(L_GETMESSAGES, &message[0], sizeof(message)) != -1) {
 
1183
    ERRBUF_APPEND("Please issue below command for detailed reasons:\n\t");
 
1184
    ERRBUF_APPEND("/usr/sbin/execerror ruby ");
 
1185
    for (i=0; message[i]; i++) {
 
1186
      ERRBUF_APPEND("\"");
 
1187
      ERRBUF_APPEND(message[i]);
 
1188
      ERRBUF_APPEND("\" ");
1197
1189
    }
1198
 
    errbuf[strlen(errbuf)-1] = '\0';    /* trim off last newline */
1199
 
    rb_loaderror("%s", errbuf);
1200
 
    return;
 
1190
    ERRBUF_APPEND("\n");
 
1191
  } else {
 
1192
    ERRBUF_APPEND(strerror(errno));
 
1193
    ERRBUF_APPEND("[loadquery failed]");
 
1194
  }
 
1195
  dln_loaderror("%s", errbuf);
1201
1196
}
1202
1197
#endif
1203
1198
 
1204
 
#endif /* NO_DLN_LOAD */
 
1199
#if defined(DLN_NEEDS_ALT_SEPARATOR) && DLN_NEEDS_ALT_SEPARATOR
 
1200
#define translit_separator(src) do { \
 
1201
        char *tmp = ALLOCA_N(char, strlen(src) + 1), *p = tmp, c; \
 
1202
        do { \
 
1203
            *p++ = ((c = *file++) == '/') ? DLN_NEEDS_ALT_SEPARATOR : c; \
 
1204
        } while (c); \
 
1205
        src = tmp; \
 
1206
    } while (0)
 
1207
#else
 
1208
#define translit_separator(str) (void)(str)
 
1209
#endif
1205
1210
 
1206
1211
void*
1207
1212
dln_load(const char *file)
1208
1213
{
1209
 
#ifdef NO_DLN_LOAD
1210
 
    rb_raise(rb_eLoadError, "this executable file can't load extension libraries");
1211
 
#else
1212
 
 
1213
1214
#if !defined(_AIX) && !defined(NeXT)
1214
1215
    const char *error = 0;
1215
1216
#define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
1221
1222
    void (*init_fct)();
1222
1223
    char *buf;
1223
1224
 
1224
 
    if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long");
 
1225
    if (strlen(file) >= MAXPATHLEN) dln_loaderror("filename too long");
1225
1226
 
1226
1227
    /* Load the file as an object one */
1227
1228
    init_funcname(&buf, file);
1228
1229
 
1229
 
    strcpy(winfile, file);
 
1230
    strlcpy(winfile, file, sizeof(winfile));
1230
1231
 
1231
1232
    /* Load file */
1232
1233
    if ((handle = LoadLibrary(winfile)) == NULL) {
1235
1236
    }
1236
1237
 
1237
1238
    if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
1238
 
        rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
 
1239
        dln_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
1239
1240
    }
1240
1241
 
1241
1242
    /* Call the init code */
1253
1254
    char *buf;
1254
1255
    /* Load the file as an object one */
1255
1256
    init_funcname(&buf, file);
 
1257
    translit_separator(file);
1256
1258
 
1257
1259
#ifdef USE_DLN_DLOPEN
1258
1260
#define DLN_DEFINED
1276
1278
            goto failed;
1277
1279
        }
1278
1280
 
1279
 
        init_fct = (void(*)())dlsym(handle, buf);
 
1281
        init_fct = (void(*)())(VALUE)dlsym(handle, buf);
 
1282
#if defined __SYMBIAN32__
 
1283
        if (init_fct == NULL) {
 
1284
            init_fct = (void(*)())dlsym(handle, "1"); /* Some Symbian versions do not support symbol table in DLL, ordinal numbers only */
 
1285
        }
 
1286
#endif
1280
1287
        if (init_fct == NULL) {
1281
1288
            error = DLN_ERROR();
1282
1289
            dlclose(handle);
1300
1307
        lib = shl_load(file, flags, 0);
1301
1308
        if (lib == NULL) {
1302
1309
            extern int errno;
1303
 
            rb_loaderror("%s - %s", strerror(errno), file);
 
1310
            dln_loaderror("%s - %s", strerror(errno), file);
1304
1311
        }
1305
1312
        shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
1306
1313
        if (init_fct == NULL) {
1307
1314
            shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
1308
1315
            if (init_fct == NULL) {
1309
1316
                errno = ENOSYM;
1310
 
                rb_loaderror("%s - %s", strerror(ENOSYM), file);
 
1317
                dln_loaderror("%s - %s", strerror(ENOSYM), file);
1311
1318
            }
1312
1319
        }
1313
1320
        (*init_fct)();
1336
1343
#define DLN_DEFINED
1337
1344
/*----------------------------------------------------
1338
1345
   By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
1339
 
 
 
1346
 
1340
1347
   Special Thanks...
1341
1348
    Yu tomoak-i@is.aist-nara.ac.jp,
1342
1349
    Mi hisho@tasihara.nest.or.jp,
1351
1358
        char *object_files[2] = {NULL, NULL};
1352
1359
 
1353
1360
        void (*init_fct)();
1354
 
        
 
1361
 
1355
1362
        object_files[0] = (char*)file;
1356
 
        
 
1363
 
1357
1364
        s = NXOpenFile(2,NX_WRITEONLY);
1358
1365
 
1359
1366
        /* Load object file, if return value ==0 ,  load failed*/
1360
1367
        if(rld_load(s, NULL, object_files, NULL) == 0) {
1361
1368
            NXFlush(s);
1362
1369
            NXClose(s);
1363
 
            rb_loaderror("Failed to load %.200s", file);
 
1370
            dln_loaderror("Failed to load %.200s", file);
1364
1371
        }
1365
1372
 
1366
1373
        /* lookup the initial function */
1367
1374
        if(rld_lookup(s, buf, &init_address) == 0) {
1368
1375
            NXFlush(s);
1369
1376
            NXClose(s);
1370
 
            rb_loaderror("Failed to lookup Init function %.200s", file);
 
1377
            dln_loaderror("Failed to lookup Init function %.200s", file);
1371
1378
        }
1372
1379
 
1373
1380
        NXFlush(s);
1374
1381
        NXClose(s);
1375
1382
 
1376
1383
        /* Cannot call *init_address directory, so copy this value to
1377
 
           funtion pointer */
 
1384
           function pointer */
1378
1385
        init_fct = (void(*)())init_address;
1379
1386
        (*init_fct)();
1380
1387
        return (void*)init_address;
1392
1399
        dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
1393
1400
 
1394
1401
        if (dyld_result != NSObjectFileImageSuccess) {
1395
 
            rb_loaderror("Failed to load %.200s", file);
 
1402
            dln_loaderror("Failed to load %.200s", file);
1396
1403
        }
1397
1404
 
1398
1405
        NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
1399
1406
 
1400
1407
        /* lookup the initial function */
1401
1408
        if(!NSIsSymbolNameDefined(buf)) {
1402
 
            rb_loaderror("Failed to lookup Init function %.200s",file);
1403
 
        }       
 
1409
            dln_loaderror("Failed to lookup Init function %.200s",file);
 
1410
        }
1404
1411
        init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
1405
1412
        (*init_fct)();
1406
1413
 
1409
1416
#endif /* rld or dyld */
1410
1417
#endif
1411
1418
 
1412
 
#ifdef __BEOS__
 
1419
#if defined(__BEOS__) || defined(__HAIKU__)
1413
1420
# define DLN_DEFINED
1414
1421
    {
1415
1422
      status_t err_stat;  /* BeOS error status code */
1416
 
      image_id img_id;    /* extention module unique id */
1417
 
      void (*init_fct)(); /* initialize function for extention module */
 
1423
      image_id img_id;    /* extension module unique id */
 
1424
      void (*init_fct)(); /* initialize function for extension module */
1418
1425
 
1419
 
      /* load extention module */
 
1426
      /* load extension module */
1420
1427
      img_id = load_add_on(file);
1421
1428
      if (img_id <= 0) {
1422
 
        rb_loaderror("Failed to load add_on %.200s error_code=%x",
 
1429
        dln_loaderror("Failed to load add_on %.200s error_code=%x",
1423
1430
          file, img_id);
1424
1431
      }
1425
 
      
 
1432
 
1426
1433
      /* find symbol for module initialize function. */
1427
1434
      /* The Be Book KernelKit Images section described to use
1428
1435
         B_SYMBOL_TYPE_TEXT for symbol of function, not
1443
1450
 
1444
1451
      if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
1445
1452
        unload_add_on(img_id);
1446
 
        rb_loaderror("Failed to lookup Init function %.200s", file);
 
1453
        dln_loaderror("Failed to lookup Init function %.200s", file);
1447
1454
      }
1448
1455
      else if (B_NO_ERROR != err_stat) {
1449
1456
        char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
1450
1457
        unload_add_on(img_id);
1451
 
        rb_loaderror(errmsg, strerror(err_stat), buf);
 
1458
        dln_loaderror(errmsg, strerror(err_stat), buf);
1452
1459
      }
1453
1460
 
1454
1461
      /* call module initialize function. */
1455
1462
      (*init_fct)();
1456
1463
      return (void*)img_id;
1457
1464
    }
1458
 
#endif /* __BEOS__*/
 
1465
#endif /* __BEOS__ || __HAIKU__ */
1459
1466
 
1460
1467
#ifndef DLN_DEFINED
1461
 
    rb_notimplement();
 
1468
    dln_notimplement();
1462
1469
#endif
1463
1470
 
1464
1471
#endif /* USE_DLN_A_OUT */
1465
1472
#endif
1466
1473
#if !defined(_AIX) && !defined(NeXT)
1467
1474
  failed:
1468
 
    rb_loaderror("%s - %s", error, file);
 
1475
    dln_loaderror("%s - %s", error, file);
1469
1476
#endif
1470
1477
 
1471
 
#endif /* NO_DLN_LOAD */
1472
1478
    return 0;                   /* dummy return */
1473
1479
}
1474
 
 
1475
 
static char *dln_find_1(const char *fname, const char *path, char *buf, int size, int exe_flag);
1476
 
 
1477
 
char *
1478
 
dln_find_exe_r(const char *fname, const char *path, char *buf, int size)
1479
 
{
1480
 
    if (!path) {
1481
 
        path = getenv(PATH_ENV);
1482
 
    }
1483
 
 
1484
 
    if (!path) {
1485
 
#if defined(_WIN32)
1486
 
        path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
1487
 
#else
1488
 
        path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
1489
 
#endif
1490
 
    }
1491
 
    return dln_find_1(fname, path, buf, size, 1);
1492
 
}
1493
 
 
1494
 
char *
1495
 
dln_find_file_r(const char *fname, const char *path, char *buf, int size)
1496
 
{
1497
 
    if (!path) path = ".";
1498
 
    return dln_find_1(fname, path, buf, size, 0);
1499
 
}
1500
 
 
1501
 
static char fbuf[MAXPATHLEN];
1502
 
 
1503
 
char *
1504
 
dln_find_exe(const char *fname, const char *path)
1505
 
{
1506
 
    return dln_find_exe_r(fname, path, fbuf, sizeof(fbuf));
1507
 
}
1508
 
 
1509
 
char *
1510
 
dln_find_file(const char *fname, const char *path)
1511
 
{
1512
 
    return dln_find_file_r(fname, path, fbuf, sizeof(fbuf));
1513
 
}
1514
 
 
1515
 
static char *
1516
 
dln_find_1(const char *fname, const char *path, char *fbuf, int size,
1517
 
           int exe_flag /* non 0 if looking for executable. */)
1518
 
{
1519
 
    register const char *dp;
1520
 
    register const char *ep;
1521
 
    register char *bp;
1522
 
    struct stat st;
1523
 
    int i, fspace;
1524
 
#ifdef DOSISH
1525
 
    static const char extension[][5] = {
1526
 
        ".exe", ".com", ".cmd", ".bat",
1527
 
    };
1528
 
    size_t j;
1529
 
    int is_abs = 0, has_path = 0;
1530
 
    const char *ext = 0;
1531
 
    const char *p = fname;
1532
 
#endif
1533
 
 
1534
 
#define RETURN_IF(expr) if (expr) return (char *)fname;
1535
 
 
1536
 
    RETURN_IF(!fname);
1537
 
#ifdef DOSISH
1538
 
# ifndef CharNext
1539
 
# define CharNext(p) ((p)+1)
1540
 
# endif
1541
 
# ifdef DOSISH_DRIVE_LETTER
1542
 
    if (((p[0] | 0x20) - 'a') < 26  && p[1] == ':') {
1543
 
        p += 2;
1544
 
        is_abs = 1;
1545
 
    }
1546
 
# endif
1547
 
    switch (*p) {
1548
 
      case '/': case '\\':
1549
 
        is_abs = 1;
1550
 
        p++;
1551
 
    }
1552
 
    has_path = is_abs;
1553
 
    while (*p) {
1554
 
        switch (*p) {
1555
 
          case '/': case '\\':
1556
 
            has_path = 1;
1557
 
            ext = 0;
1558
 
            p++;
1559
 
            break;
1560
 
          case '.':
1561
 
            ext = p;
1562
 
            p++;
1563
 
            break;
1564
 
          default:
1565
 
            p = CharNext(p);
1566
 
        }
1567
 
    }
1568
 
    if (ext) {
1569
 
        for (j = 0; STRCASECMP(ext, extension[j]); ) {
1570
 
            if (++j == sizeof(extension) / sizeof(extension[0])) {
1571
 
                ext = 0;
1572
 
                break;
1573
 
            }
1574
 
        }
1575
 
    }
1576
 
    ep = bp = 0;
1577
 
    if (!exe_flag) {
1578
 
        RETURN_IF(is_abs);
1579
 
    }
1580
 
    else if (has_path) {
1581
 
        RETURN_IF(ext);
1582
 
        i = p - fname;
1583
 
        if (i + 1 > size) goto toolong;
1584
 
        fspace = size - i - 1;
1585
 
        bp = fbuf;
1586
 
        ep = p;
1587
 
        memcpy(fbuf, fname, i + 1);
1588
 
        goto needs_extension;
1589
 
    }
1590
 
#endif
1591
 
 
1592
 
    RETURN_IF(fname[0] == '/');
1593
 
    RETURN_IF(strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0);
1594
 
    RETURN_IF(exe_flag && strchr(fname, '/'));
1595
 
 
1596
 
#undef RETURN_IF
1597
 
 
1598
 
    for (dp = path;; dp = ++ep) {
1599
 
        register int l;
1600
 
 
1601
 
        /* extract a component */
1602
 
        ep = strchr(dp, PATH_SEP[0]);
1603
 
        if (ep == NULL)
1604
 
            ep = dp+strlen(dp);
1605
 
 
1606
 
        /* find the length of that component */
1607
 
        l = ep - dp;
1608
 
        bp = fbuf;
1609
 
        fspace = size - 2;
1610
 
        if (l > 0) {
1611
 
            /*
1612
 
            **  If the length of the component is zero length,
1613
 
            **  start from the current directory.  If the
1614
 
            **  component begins with "~", start from the
1615
 
            **  user's $HOME environment variable.  Otherwise
1616
 
            **  take the path literally.
1617
 
            */
1618
 
 
1619
 
            if (*dp == '~' && (l == 1 ||
1620
 
#if defined(DOSISH)
1621
 
                               dp[1] == '\\' || 
1622
 
#endif
1623
 
                               dp[1] == '/')) {
1624
 
                char *home;
1625
 
 
1626
 
                home = getenv("HOME");
1627
 
                if (home != NULL) {
1628
 
                    i = strlen(home);
1629
 
                    if ((fspace -= i) < 0)
1630
 
                        goto toolong;
1631
 
                    memcpy(bp, home, i);
1632
 
                    bp += i;
1633
 
                }
1634
 
                dp++;
1635
 
                l--;
1636
 
            }
1637
 
            if (l > 0) {
1638
 
                if ((fspace -= l) < 0)
1639
 
                    goto toolong;
1640
 
                memcpy(bp, dp, l);
1641
 
                bp += l;
1642
 
            }
1643
 
 
1644
 
            /* add a "/" between directory and filename */
1645
 
            if (ep[-1] != '/')
1646
 
                *bp++ = '/';
1647
 
        }
1648
 
 
1649
 
        /* now append the file name */
1650
 
        i = strlen(fname);
1651
 
        if ((fspace -= i) < 0) {
1652
 
          toolong:
1653
 
            fprintf(stderr, "openpath: pathname too long (ignored)\n");
1654
 
            *bp = '\0';
1655
 
            fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
1656
 
            fprintf(stderr, "\tFile \"%s\"\n", fname);
1657
 
            goto next;
1658
 
        }
1659
 
        memcpy(bp, fname, i + 1);
1660
 
 
1661
 
#if defined(DOSISH)
1662
 
        if (exe_flag && !ext) {
1663
 
          needs_extension:
1664
 
            for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
1665
 
                if (fspace < strlen(extension[j])) {
1666
 
                    fprintf(stderr, "openpath: pathname too long (ignored)\n");
1667
 
                    fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
1668
 
                    fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
1669
 
                    continue;
1670
 
                }
1671
 
                strcpy(bp + i, extension[j]);
1672
 
                if (stat(fbuf, &st) == 0)
1673
 
                    return fbuf;
1674
 
            }
1675
 
            goto next;
1676
 
        }
1677
 
#endif /* _WIN32 or __EMX__ */
1678
 
 
1679
 
        if (stat(fbuf, &st) == 0) {
1680
 
            if (exe_flag == 0) return fbuf;
1681
 
            /* looking for executable */
1682
 
            if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
1683
 
                return fbuf;
1684
 
        }
1685
 
      next:
1686
 
        /* if not, and no other alternatives, life is bleak */
1687
 
        if (*ep == '\0') {
1688
 
            return NULL;
1689
 
        }
1690
 
 
1691
 
        /* otherwise try the next component in the search path */
1692
 
    }
1693
 
}