jsfile.c
来自「一个基于alice开发的机器人」· C语言 代码 · 共 2,148 行 · 第 1/5 页
C
2,148 行
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*
* JS File object
*/
#if JS_HAS_FILE_OBJECT
#include "jsstddef.h"
/* ----------------- Platform-specific includes and defines ----------------- */
#ifdef XP_MAC
# define FILESEPARATOR ':'
# define FILESEPARATOR2 '\0'
# define CURRENT_DIR "HARD DISK:Desktop Folder"
/* TODO: #include <???> */
#elif defined(XP_WIN) || defined(XP_OS2)
# include <direct.h>
# include <io.h>
# include <sys/types.h>
# include <sys/stat.h>
# define FILESEPARATOR '\\'
# define FILESEPARATOR2 '/'
# define CURRENT_DIR "c:\\"
# define POPEN _popen
# define PCLOSE _pclose
#elif defined(XP_UNIX) || defined(XP_BEOS)
# include <strings.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# define FILESEPARATOR '/'
# define FILESEPARATOR2 '\0'
# define CURRENT_DIR "/"
# define POPEN popen
# define PCLOSE pclose
#endif
/* --------------- Platform-independent includes and defines ---------------- */
#include "jsapi.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "jsdate.h"
#include "jsdbgapi.h"
#include "jsemit.h"
#include "jsfun.h"
#include "jslock.h"
#include "jsobj.h"
#include "jsparse.h"
#include "jsscan.h"
#include "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
#include "jsutil.h" /* Added by JSIFY */
#include <string.h>
/* NSPR dependencies */
#include "prio.h"
#include "prerror.h"
#define SPECIAL_FILE_STRING "Special File"
#define CURRENTDIR_PROPERTY "currentDir"
#define SEPARATOR_PROPERTY "separator"
#define FILE_CONSTRUCTOR "File"
#define PIPE_SYMBOL '|'
#define ASCII 0
#define UTF8 1
#define UCS2 2
#define asciistring "text"
#define utfstring "binary"
#define unicodestring "unicode"
#define MAX_PATH_LENGTH 1024
#define MODE_SIZE 256
#define NUMBER_SIZE 32
#define MAX_LINE_LENGTH 256
#define URL_PREFIX "file://"
#define STDINPUT_NAME "Standard input stream"
#define STDOUTPUT_NAME "Standard output stream"
#define STDERROR_NAME "Standard error stream"
#define RESOLVE_PATH js_canonicalPath /* js_absolutePath */
/* Error handling */
typedef enum JSFileErrNum {
#define MSG_DEF(name, number, count, exception, format) \
name = number,
#include "jsfile.msg"
#undef MSG_DEF
JSFileErr_Limit
#undef MSGDEF
} JSFileErrNum;
#define JSFILE_HAS_DFLT_MSG_STRINGS 1
JSErrorFormatString JSFile_ErrorFormatString[JSFileErr_Limit] = {
#if JSFILE_HAS_DFLT_MSG_STRINGS
#define MSG_DEF(name, number, count, exception, format) \
{ format, count } ,
#else
#define MSG_DEF(name, number, count, exception, format) \
{ NULL, count } ,
#endif
#include "jsfile.msg"
#undef MSG_DEF
};
const JSErrorFormatString *
JSFile_GetErrorMessage(void *userRef, const char *locale,
const uintN errorNumber)
{
if ((errorNumber > 0) && (errorNumber < JSFileErr_Limit))
return &JSFile_ErrorFormatString[errorNumber];
else
return NULL;
}
#define JSFILE_CHECK_NATIVE(op) \
if(file->isNative){ \
JS_ReportWarning(cx, "Cannot call or access \"%s\" on native file %s", \
op, file->path); \
goto out; \
}
#define JSFILE_CHECK_WRITE \
if (!file->isOpen){ \
JS_ReportWarning(cx, \
"File %s is closed, will open it for writing, proceeding", \
file->path); \
js_FileOpen(cx, obj, file, "write,append,create"); \
}else \
if(!js_canWrite(cx, file)){ \
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
JSFILEMSG_CANNOT_WRITE, file->path); \
goto out; \
}
#define JSFILE_CHECK_READ \
if (!file->isOpen){ \
JS_ReportWarning(cx, \
"File %s is closed, will open it for reading, proceeding", \
file->path); \
js_FileOpen(cx, obj, file, "read"); \
}else \
if(!js_canRead(cx, file)){ \
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
JSFILEMSG_CANNOT_READ, file->path); \
goto out; \
}
#define JSFILE_CHECK_OPEN(op) \
if(!file->isOpen){ \
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
JSFILEMSG_FILE_MUST_BE_CLOSED, op); \
goto out; \
}
#define JSFILE_CHECK_CLOSED(op) \
if(file->isOpen){ \
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
JSFILEMSG_FILE_MUST_BE_OPEN, op); \
goto out; \
}
#define JSFILE_CHECK_ONE_ARG(op) \
if (argc!=1){ \
char str[NUMBER_SIZE]; \
\
sprintf(str, "%d", argc); \
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL, \
JSFILEMSG_EXPECTS_ONE_ARG_ERROR, op, str); \
goto out; \
}
/*
Security mechanism, should define a callback for this.
The parameters are as follows:
SECURITY_CHECK(JSContext *cx, JSPrincipals *ps, char *op_name, JSFile *file)
*/
#define SECURITY_CHECK(cx, ps, op, file) \
/* Define a callback here... */
/* Structure representing the file internally */
typedef struct JSFile {
char *path; /* the path to the file. */
JSBool isOpen;
JSString *linebuffer; /* temp buffer used by readln. */
int32 mode; /* mode used to open the file: read, write, append, create, etc.. */
int32 type; /* Asciiz, utf, unicode */
char byteBuffer[3]; /* bytes read in advance by js_FileRead ( UTF8 encoding ) */
jsint nbBytesInBuf; /* number of bytes stored in the buffer above */
jschar charBuffer; /* character read in advance by readln ( mac files only ) */
JSBool charBufferUsed; /* flag indicating if the buffer above is being used */
JSBool hasRandomAccess; /* can the file be randomly accessed? false for stdin, and
UTF-encoded files. */
JSBool hasAutoflush; /* should we force a flush for each line break? */
JSBool isNative; /* if the file is using OS-specific file FILE type */
/* We can actually put the following two in a union since they should never be used at the same time */
PRFileDesc *handle; /* the handle for the file, if open. */
FILE *nativehandle; /* native handle, for stuff NSPR doesn't do. */
JSBool isPipe; /* if the file is really an OS pipe */
} JSFile;
/* a few forward declarations... */
static JSClass file_class;
JS_PUBLIC_API(JSObject*) js_NewFileObject(JSContext *cx, char *filename);
static JSBool file_open(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
static JSBool file_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
/* --------------------------- New filename manipulation procesures -------------------------- */
/* assumes we don't have leading/trailing spaces */
static JSBool
js_filenameHasAPipe(const char *filename)
{
#ifdef XP_MAC
/* pipes are not supported on the MAC */
return JS_FALSE;
#else
if(!filename) return JS_FALSE;
return filename[0]==PIPE_SYMBOL ||
filename[strlen(filename)-1]==PIPE_SYMBOL;
#endif
}
static JSBool
js_isAbsolute(const char *name)
{
#if defined(XP_WIN) || defined(XP_OS2)
return (strlen(name)>1)?((name[1]==':')?JS_TRUE:JS_FALSE):JS_FALSE;
#else
return (name[0]
# if defined(XP_UNIX) || defined(XP_BEOS)
==
# else
!=
# endif
FILESEPARATOR)?JS_TRUE:JS_FALSE;
#endif
}
/*
Concatinates base and name to produce a valid filename.
Returned string must be freed.
*/
static char*
js_combinePath(JSContext *cx, const char *base, const char *name)
{
int len = strlen(base);
char* result = (char*)JS_malloc(cx, len+strlen(name)+2);
if (!result) return NULL;
strcpy(result, base);
if (base[len-1]!=FILESEPARATOR
#if defined(XP_WIN) || defined(XP_OS2)
&& base[len-1]!=FILESEPARATOR2
#endif
) {
result[len] = FILESEPARATOR;
result[len+1] = '\0';
}
strcat(result, name);
return result;
}
/* Extract the last component from a path name. Returned string must be freed */
static char *
js_fileBaseName(JSContext *cx, const char *pathname)
{
jsint index, aux;
char *result;
#if defined(XP_WIN) || defined(XP_OS2)
/* First, get rid of the drive selector */
if ((strlen(pathname)>=2)&&(pathname[1]==':')) {
pathname = &pathname[2];
}
#endif
index = strlen(pathname)-1;
/*
remove trailing separators -- don't necessarily need to check for
FILESEPARATOR2, but that's fine
*/
while ((index>0)&&((pathname[index]==FILESEPARATOR)||
(pathname[index]==FILESEPARATOR2))) index--;
aux = index;
/* now find the next separator */
while ((index>=0)&&(pathname[index]!=FILESEPARATOR)&&
(pathname[index]!=FILESEPARATOR2)) index--;
/* allocate and copy */
result = (char*)JS_malloc(cx, aux-index+1);
if (!result) return NULL;
strncpy(result, &pathname[index+1], aux-index);
result[aux-index] = '\0';
return result;
}
/*
Returns everytynig but the last component from a path name.
Returned string must be freed. Returned string must be freed.
*/
static char *
js_fileDirectoryName(JSContext *cx, const char *pathname)
{
jsint index;
char *result;
#if defined(XP_WIN) || defined(XP_OS2)
char drive = '\0';
const char *oldpathname = pathname;
/* First, get rid of the drive selector */
if ((strlen(pathname)>=2)&&(pathname[1]==':')) {
drive = pathname[0];
pathname = &pathname[2];
}
#endif
index = strlen(pathname)-1;
while ((index>0)&&((pathname[index]==FILESEPARATOR)||
(pathname[index]==FILESEPARATOR2))) index--;
while ((index>0)&&(pathname[index]!=FILESEPARATOR)&&
(pathname[index]!=FILESEPARATOR2)) index--;
if (index>=0){
result = (char*)JS_malloc(cx, index+4);
if (!result) return NULL;
#if defined(XP_WIN) || defined(XP_OS2)
if (drive!='\0') {
result[0] = toupper(drive);
result[1] = ':';
strncpy(&result[2], pathname, index);
result[index+3] = '\0';
}else
#endif
{
strncpy(result, pathname, index);
result[index] = '\0';
}
/* add terminating separator */
index = strlen(result)-1;
result[index] = FILESEPARATOR;
result[index+1] = '\0';
} else{
#if defined(XP_WIN) || defined(XP_OS2)
result = JS_strdup(cx, oldpathname); /* may include drive selector */
#else
result = JS_strdup(cx, pathname);
#endif
}
return result;
}
static char *
js_absolutePath(JSContext *cx, const char * path)
{
JSObject *obj;
JSString *str;
jsval prop;
if (js_isAbsolute(path)){
return JS_strdup(cx, path);
}else{
obj = JS_GetGlobalObject(cx);
if (!JS_GetProperty(cx, obj, FILE_CONSTRUCTOR, &prop)) {
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR);
return JS_strdup(cx, path);
}
obj = JSVAL_TO_OBJECT(prop);
if (!JS_GetProperty(cx, obj, CURRENTDIR_PROPERTY, &prop)) {
JS_ReportErrorNumber(cx, JSFile_GetErrorMessage, NULL,
JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR);
return JS_strdup(cx, path);
}
str = JS_ValueToString(cx, prop);
if (!str ) {
return JS_strdup(cx, path);
}
/* should we have an array of curr dirs indexed by drive for windows? */
return js_combinePath(cx, JS_GetStringBytes(str), path);
}
}
/* Side effect: will remove spaces in the beginning/end of the filename */
static char *
js_canonicalPath(JSContext *cx, char *oldpath)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?