root/NEWT0/trunk/src/newt_core/NewtFile.c

Revision 113, 14.4 kB (checked in by gnue, 17 months ago)

'#pragma mark' is invalidated by '#if 0'

Line 
1/*------------------------------------------------------------------------*/
2/**
3 * @file    NewtFile.c
4 * @brief   ファイル処理
5 *
6 * @author  M.Nukui
7 * @date    2004-01-25
8 *
9 * Copyright (C) 2003-2004 M.Nukui All rights reserved.
10 */
11
12
13/* ヘッダファイル */
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17
18#include "NewtType.h"
19
20
21#if defined(__WIN32__)
22    #include "win/dlfcn.h"
23#elif defined(HAVE_DLOPEN)
24    #include <dlfcn.h>
25#endif
26
27#ifdef HAVE_GETPWNAM
28    #include <pwd.h>
29#endif /* HAVE_GETPWNAM */
30
31
32#include "NewtCore.h"
33#include "NewtVM.h"
34#include "NewtBC.h"
35#include "NewtIO.h"
36#include "NewtFile.h"
37
38
39/* 定数 */
40
41enum {
42    typeScript,
43    typeDylib,
44};
45
46
47/* 型宣言 */
48
49/// ファイル拡張子
50typedef struct {
51    newtRefVar  ext;    ///< 拡張子
52    int         type;   ///< タイプ
53} file_ext_t;
54
55
56#ifdef HAVE_DLOPEN
57/*------------------------------------------------------------------------*/
58/** 動的ライブラリをインストールする
59 *
60 * @param fname     [in] ファイルのパス
61 *
62 * @return          動的ライブラリのデスクプリタ
63 */
64
65void * NewtDylibInstall(const char * fname)
66{
67    newt_install_t  install_call;
68    void *  lib;
69
70    lib = dlopen(fname, RTLD_LAZY);
71
72    if (lib != NULL)
73    {
74        install_call = (newt_install_t)dlsym(lib, "newt_install");
75
76        if (install_call == NULL)
77        {
78            dlclose(lib);
79            return NULL;
80        }
81
82        (*install_call)();
83    }
84
85    return lib;
86}
87
88#endif /* HAVE_DLOPEN */
89
90
91/*------------------------------------------------------------------------*/
92/** ファイルの存在確認
93 *
94 * @param path      [in] ファイルのパス
95 *
96 * @retval          true    ファイルが存在する
97 * @retval          false   ファイルが存在しない
98 */
99
100bool NewtFileExists(char * path)
101{
102    FILE *  f;
103
104    f = fopen(path, "r");
105
106    if (f != NULL)
107    {
108        fclose(f);
109        return true;
110    }
111
112    return false;
113}
114
115
116#if 0
117#pragma mark -
118#endif
119/*------------------------------------------------------------------------*/
120/** ファイルセパレータを返す
121 *
122 * @return          ファイルセパレータ
123 */
124
125char NewtGetFileSeparator(void)
126{
127    return '/';
128}
129
130
131/*------------------------------------------------------------------------*/
132/** ホームディレクトリのパスを取得
133 *
134 * @param s         [in] ファイルのパス
135 * @param subdir    [out]サブディレクトリ
136 *
137 * @return          ホームディレクトリのパス
138 *
139 * @note            取得されたホームディレクトリの文字列は free する必要がある
140 */
141
142#ifdef HAVE_GETPWNAM
143
144char * NewtGetHomeDir(const char * s, char ** subdir)
145{   // UNIX の場合
146    struct passwd * pswd = NULL;
147    uint32_t    len;
148    char *  login = NULL;
149    char *  dir = NULL;
150    char *  sepp;
151    char    sep;
152
153    sep = NewtGetFileSeparator();
154    sepp = strchr(s + 1, sep);
155
156    if (sepp != NULL)
157    {
158        len = sepp - (s + 1);
159        login = malloc(len + 1);
160        strncpy(login, s + 1, len);
161        pswd = getpwnam(s + 1);
162    }
163    else
164    {
165        login = (char *)s + 1;
166    }
167
168    if (*login)
169        pswd = getpwnam(login);
170    else
171        pswd = getpwuid(getuid());
172
173    if (pswd != NULL)
174        dir = pswd->pw_dir;
175
176    if (subdir != NULL)
177        *subdir = sepp;
178
179    if (s + 1 != login)
180        free(login);
181
182    return dir;
183}
184
185#else
186
187char * NewtGetHomeDir(const char * s, char ** subdir)
188{   // Windows の場合
189    return NULL;
190}
191
192#endif /* HAVE_GETPWNAM */
193
194
195/*------------------------------------------------------------------------*/
196/** ディレクトリ名とファイル名からパスを作成
197 *
198 * @param s1        [in] ディレクトリ名
199 * @param s2        [in] ファイル名
200 * @param sep       [in] ファイルセパレータ
201 *
202 * @return          作成されたパス
203 *
204 * @note            取得されたホームディレクトリの文字列は free する必要がある
205 */
206
207char * NewtJoinPath(char * s1, char * s2, char sep)
208{
209    char *      path;
210    uint32_t    len;
211    uint32_t    len1;
212    uint32_t    len2;
213
214    len1 = strlen(s1);
215    len2 = strlen(s2);
216
217    len = len1 + len2 + 2;
218
219    path = malloc(len);
220    if (path == NULL) return NULL;
221
222    strcpy(path, s1);
223
224    path[len1] = sep;
225    strncpy(path + len1 + 1, s2, len2 + 1);
226
227    return path;
228}
229
230
231/*------------------------------------------------------------------------*/
232/** 相対パスを絶対パスに展開する
233 *
234 * @param s         [i/o]相対パス→絶対パス
235 *
236 * @return          絶対パス
237 */
238
239char * NewtRelToAbsPath(char * s)
240{
241    char *  src;
242    char *  dst;
243    char    sep;
244
245    sep = NewtGetFileSeparator();
246
247    for (src = dst = s; *src;)
248    {
249        if (src[0] == sep && src[1] == '.')
250        {
251            if (src[2] == sep || ! src[2])
252            {
253                src += 2;
254                continue;
255            }
256            else if (src[2] == '.' && src[3] == sep)
257            {
258                src += 3;
259
260                while (s < dst)
261                {
262                    dst--;
263                    if (*dst == sep) break;
264                }
265
266                continue;
267            }
268        }
269
270        if (src != dst)
271            *dst = *src;
272
273        src++;
274        dst++;
275    }
276
277    if (s < dst && *(dst - 1) == sep)
278        *(dst - 1) = '\0';
279    else if (src != dst)
280        *dst = '\0';
281
282    return s;
283}
284
285
286/*------------------------------------------------------------------------*/
287/** 相対パスを絶対パスに展開する
288 *
289 * @param s         [in] 相対パス(C文字列)
290 *
291 * @return          絶対パス(文字列オブジェクト)
292 *
293 * @note            ~, ~user はホームディレクトリに展開される
294 */
295
296newtRef NewtExpandPath(const char * s)
297{
298    newtRefVar  r = kNewtRefUnbind;
299    char *  subdir = NULL;
300    char *  dir = NULL;
301    char *  wd = NULL;
302    char    sep;
303
304    sep = NewtGetFileSeparator();
305
306    if (*s == sep)
307    {
308        dir = (char *)s;
309    }
310#ifdef __WIN32__
311    else if (isalpha(*s) && s[1] == ':')
312    {
313        dir = (char *)s;
314    }
315#endif
316    else if (*s == '~')
317    {
318        dir = NewtGetHomeDir(s, &subdir);
319
320        if (subdir != NULL && subdir[1])
321            subdir++;
322        else
323            subdir = NULL;
324    }
325    else
326    {
327        subdir = (char *)s;
328    }
329
330    if (dir == NULL)
331#ifdef HAVE_GETCWD
332        dir = wd = getcwd(NULL, 0);
333#else
334        dir = "";
335#endif /* HAVE_GETCWD */
336
337    if (subdir != NULL)
338    {
339        dir = NewtJoinPath(dir, subdir, sep);
340        NewtRelToAbsPath(dir);
341    }
342
343    r = NSSTR(dir);
344
345    if (subdir != NULL)
346        free(dir);
347
348    if (wd != NULL)
349        free(wd);
350
351    return r;
352}
353
354
355#if 0
356#pragma mark -
357#endif
358/*------------------------------------------------------------------------*/
359/** パスからファイル名を取出す
360 *
361 * @param s         [in] パスへのポインタ
362 * @param len       [in] パスの文字数
363 *
364 * @return          ファイル名
365 */
366
367char * NewtBaseName(char * s, uint32_t len)
368{
369    uint32_t    base = 0;
370    uint32_t    i;
371    char        sep;
372
373    sep = NewtGetFileSeparator();
374
375    for (i = 0; i < len; i++)
376    {
377        if (s[i] == sep)
378            base = i + 1;
379    }
380
381    if (base < len)
382        return (s + base);
383    else
384        return NULL;
385}
386
387
388#if 0
389#pragma mark -
390#endif
391/*------------------------------------------------------------------------*/
392/** ソースファイルのコンパイル
393 *
394 * @param rcvr      [in] レシーバ
395 * @param r         [in] コンパイルするソースファイルのパス
396 *
397 * @return          引数 0 の関数オブジェクト
398 */
399
400newtRef NsCompileFile(newtRefArg rcvr, newtRefArg r)
401{
402    char *  fname;
403
404    if (! NewtRefIsString(r))
405        return NewtThrow(kNErrNotAString, r);
406
407    fname = NewtRefToString(r);
408
409    return NBCCompileFile(fname, true);
410}
411
412
413/*------------------------------------------------------------------------*/
414/** ライブラリのロード
415 *
416 * @param rcvr      [in] レシーバ
417 * @param r         [in] ロードするライブラリのパス
418 *
419 * @return          動的ライブラリのデスクプリタ
420 */
421
422#ifdef HAVE_DLOPEN
423
424newtRef NsLoadLib(newtRefArg rcvr, newtRefArg r)
425{
426    char *  fname;
427    void *  lib;
428
429    if (! NewtRefIsString(r))
430        return NewtThrow(kNErrNotAString, r);
431
432    fname = NewtRefToString(r);
433    lib = NewtDylibInstall(fname);
434
435    if (lib != NULL)
436    {
437        return NewtMakeInteger((int32_t)lib);
438    }
439    else
440    {
441        const char *  errmsg;
442
443        errmsg = dlerror();
444
445        if (errmsg != NULL)
446        {
447            NewtFprintf(stderr,"%s\n", errmsg);
448        }
449
450        return NewtThrow(kNErrDylibNotOpen, r);
451    }
452}
453
454#endif /* HAVE_DLOPEN */
455
456
457
458/*------------------------------------------------------------------------*/
459/** ソースファイルのロード
460 *
461 * @param rcvr      [in] レシーバ
462 * @param r         [in] ロードするソースファイルのパス
463 *
464 * @return          実行結果のオブジェクト
465 */
466
467newtRef NsLoad(newtRefArg rcvr, newtRefArg r)
468{
469    newtRefVar  result = kNewtRefUnbind;
470    newtRefVar  fn;
471
472    fn = NsCompileFile(rcvr, r);
473
474    if (NewtRefIsNotNIL(fn))
475        result = NVMCall(fn, 0, NULL);
476
477    return result;
478}
479
480
481/*------------------------------------------------------------------------*/
482/** ライブラリの要求
483 *
484 * @param r         [in] ロードするライブラリのシンボル文字列
485 *
486 * @return          ロードされたライブラリのシンボル
487 *
488 * @note            シンボルによりライブラリを要求する。
489 *                  拡張子は必要ない。適宜ライブラリパスにより検索される。
490 *                  一度ロードされたライブラリは読込まれない。
491 *                  ライブラリが見つからなくても例外は発生しない。
492 */
493
494newtRef NcRequire0(newtRefArg r)
495{
496    newtRefVar  newtlib;
497    newtRefVar  requires;
498    newtRefVar  sym;
499    newtRefVar  env;
500
501    if (NewtRefIsSymbol(r))
502    {
503        sym = r;
504    }
505    else
506    {
507        if (! NewtRefIsString(r))
508            return NewtThrow(kNErrNotASymbol, r);
509
510        sym = NcMakeSymbol(r);
511    }
512
513    requires = NcGetGlobalVar(NSSYM0(requires));
514
515    if (! NewtRefIsFrame(requires))
516    {
517        requires = NcMakeFrame();
518        NcDefGlobalVar(NSSYM0(requires), requires);
519    }
520
521    if (NewtHasSlot(requires, sym))
522        return kNewtRefNIL;
523
524    {
525        newtRefVar  initObj[] = {kNewtRefUnbind, kNewtRefUnbind};
526        file_ext_t  lib_exts[] = {
527
528#ifdef HAVE_DLOPEN
529/*
530            {NSSTR(".dylib"),           typeDylib},
531            {NSSTR(".so"),              typeDylib},
532            {NSSTR(".dll"),             typeDylib},
533*/
534            {NSSTR(__DYLIBSUFFIX__),    typeDylib},
535#endif /* HAVE_DLOPEN */
536
537            {NSSTR(".newt"),            typeScript},
538        };
539
540        newtRefVar  lib;
541        newtRefVar  dir;
542        newtRefVar  patharray;
543        newtRefVar  path;
544        uint32_t    len;
545        uint32_t    nb_suffixes;
546        uint32_t    i;
547        uint32_t    j;
548
549        patharray = NewtMakeArray2(kNewtRefNIL, sizeof(initObj) / sizeof(newtRefVar), initObj);
550
551        env = NcGetGlobalVar(NSSYM0(_ENV_));
552        newtlib = NcGetVariable(env, NSSYM0(NEWTLIB));
553
554        if (NewtRefIsNIL(newtlib))
555        {
556            newtRefVar  initPath[] = {NSSTR(__LIBDIR__), NSSTR(".")};
557            newtlib = NewtMakeArray2(kNewtRefNIL, sizeof(initPath) / sizeof(newtRefVar), initPath);
558        }
559
560        len = NewtLength(newtlib);
561        nb_suffixes = sizeof(lib_exts) / sizeof(lib_exts[0]);
562
563        for (j = 0; j < nb_suffixes; j++)
564        {
565            NewtSetArraySlot(patharray, 1, lib_exts[j].ext);
566
567            for (i = 0; i <= len; i++)
568            {
569                if (i == len) {
570                    dir = NcGetGlobalVar(NSSYM0(_EXEDIR_));
571                } else {
572                    dir = NewtGetArraySlot(newtlib, i);
573                }
574                if (NewtRefIsString(dir))
575                {
576                    NewtSetArraySlot(patharray, 0, NcJoinPath(dir, r));
577                    path = NcStringer(patharray);
578
579                    if (NewtFileExists(NewtRefToString(path)))
580                    {
581#ifdef HAVE_DLOPEN
582                        if (lib_exts[j].type == typeDylib)
583                        {
584                            lib = NcLoadLib(path);
585                            NcSetSlot(requires, sym, lib);
586                        }
587                        else
588#endif /* HAVE_DLOPEN */
589                        {
590                            NcSetSlot(requires, sym, path);
591                            NcLoad(path);
592                        }
593   
594                        return sym;
595                    }
596                }
597            }
598        }
599    }
600
601    return kNewtRefUnbind;
602}
603
604
605/*------------------------------------------------------------------------*/
606/** ライブラリの要求
607 *
608 * @param rcvr      [in] レシーバ
609 * @param r         [in] ロードするライブラリのシンボル文字列
610 *
611 * @return          ロードされたライブラリのシンボル
612 *
613 * @note            シンボルによりライブラリを要求する。
614 *                  拡張子は必要ない。適宜ライブラリパスにより検索される。
615 *                  一度ロードされたライブラリは読込まれない。
616 */
617
618newtRef NsRequire(newtRefArg rcvr, newtRefArg r)
619{
620    newtRefVar  result;
621
622    result = NcRequire0(r);
623
624    if (result == kNewtRefUnbind)
625        NewtThrow(kNErrFileNotFound, r);
626
627    return result;
628}
629
630
631#if 0
632#pragma mark -
633#endif
634/*------------------------------------------------------------------------*/
635/** ファイルの存在確認
636 *
637 * @param rcvr      [in] レシーバ
638 * @param r         [in] ファイルのパス
639 *
640 * @retval          true    ファイルが存在する
641 * @retval          false   ファイルが存在しない
642 *
643 * @note            スクリプトからの呼出し用
644 */
645
646newtRef NsFileExists(newtRefArg rcvr, newtRefArg r)
647{
648    if (! NewtRefIsString(r))
649        return NewtThrow(kNErrNotAString, r);
650
651    return NewtMakeBoolean(NewtFileExists(NewtRefToString(r)));
652}
653
654
655#if 0
656#pragma mark -
657#endif
658/*------------------------------------------------------------------------*/
659/** パスからディレクトリ名を取出す
660 *
661 * @param rcvr      [in] レシーバ
662 * @param r         [in] ファイルのパス
663 *
664 * @return          ディレクトリ名
665 */
666
667newtRef NsDirName(newtRefArg rcvr, newtRefArg r)
668{
669    char *  base;
670    char *  s;
671    char    sep;
672
673    if (! NewtRefIsString(r))
674        return NewtThrow(kNErrNotAString, r);
675
676    s = NewtRefToString(r);
677    base = NewtBaseName(s, NewtStringLength(r));
678    sep = NewtGetFileSeparator();
679
680    if (base != NULL && s < base)
681    {
682        if (base - 1 != s && *(base - 1) == sep)
683            base--;
684
685        if (s < base)
686            return NewtMakeString2(s, base - s, false);
687    }
688
689    return NSSTR(".");
690}
691
692
693/*------------------------------------------------------------------------*/
694/** パスからファイル名を取出す
695 *
696 * @param rcvr      [in] レシーバ
697 * @param r         [in] ファイルのパス
698 *
699 * @return          ファイル名
700 *
701 * @note            スクリプトからの呼出し用
702 */
703
704newtRef NsBaseName(newtRefArg rcvr, newtRefArg r)
705{
706    char *  base;
707
708    if (! NewtRefIsString(r))
709        return NewtThrow(kNErrNotAString, r);
710
711    base = NewtBaseName(NewtRefToString(r), NewtStringLength(r));
712
713    if (base != NULL)
714        return NSSTR(base);
715    else
716        return r;
717}
718
719
720/*------------------------------------------------------------------------*/
721/** ディレクトリ名とファイル名からパスを作成
722 *
723 * @param rcvr      [in] レシーバ
724 * @param r1        [in] ディレクトリ名
725 * @param r2        [in] ファイル名
726 *
727 * @return          作成されたパス
728 */
729
730newtRef NsJoinPath(newtRefArg rcvr, newtRefArg r1, newtRefArg r2)
731{
732    char        sep = NewtGetFileSeparator();
733    newtRefVar  initObj[] = {r1, NewtMakeCharacter(sep), r2};
734    newtRefVar  r;
735
736    r = NewtMakeArray2(kNewtRefNIL, sizeof(initObj) / sizeof(newtRefVar), initObj);
737
738    return NcStringer(r);
739}
740
741
742/*------------------------------------------------------------------------*/
743/** 相対パスを絶対パスに展開する
744 *
745 * @param rcvr      [in] レシーバ
746 * @param r         [in] 相対パス
747 *
748 * @return          絶対パス
749 *
750 * @note            ~, ~user はホームディレクトリに展開される
751 *                  スクリプトからの呼出し用
752 */
753
754newtRef NsExpandPath(newtRefArg rcvr, newtRefArg r)
755{
756    if (! NewtRefIsString(r))
757        return NewtThrow(kNErrNotAString, r);
758
759    return NewtExpandPath(NewtRefToString(r));
760}
Note: See TracBrowser for help on using the browser.