/* LIBPAWNC.C * * A "glue file" for building the Pawn compiler as a DLL or shared library. * * Copyright (c) ITB CompuPhase, 2000-2005 * * This software is provided "as-is", without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software in * a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include #include #include #include #include "sc.h" #if defined PAWNC_DLL #if !defined(__linux__) && !defined(__APPLE__) #include "dllmain.c" #endif # define MAX_ARGS 100 # if !defined UNUSED_PARAM # define UNUSED_PARAM(p) ((void)(p)) # endif #if PAWN_CELL_SIZE==32 #define EXCOMPILER Compile32 #else #define EXCOMPILER Compile64 #endif # if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __NT__ __declspec (dllexport) void EXCOMPILER(int argc, char **argv) # else void extern __attribute__((visibility("default"))) EXCOMPILER(int argc, char **argv) # endif { pc_compile(argc, argv); } #endif /* PAWNC_DLL */ /* pc_printf() * Called for general purpose "console" output. This function prints general * purpose messages; errors go through pc_error(). The function is modelled * after printf(). */ #if PAWN_CELL_SIZE==32 #if defined __WIN32__ || defined _WIN32 || defined WIN32 __declspec (dllexport) int pc_printf(const char *message,...) #else extern int __attribute__((visibility("default"))) pc_printf(const char *message,...) #endif #else int pc_printf(const char *message, ...) #endif { #if PAWN_CELL_SIZE==32 int ret; va_list argptr; va_start(argptr,message); ret=vprintf(message,argptr); va_end(argptr); return ret; #else return 1; #endif } /* pc_error() * Called for producing error output. * number the error number (as documented in the manual) * message a string describing the error with embedded %d and %s tokens * filename the name of the file currently being parsed * firstline the line number at which the expression started on which * the error was found, or -1 if there is no "starting line" * lastline the line number at which the error was detected * argptr a pointer to the first of a series of arguments (for macro * "va_arg") * Return: * If the function returns 0, the parser attempts to continue compilation. * On a non-zero return value, the parser aborts. */ int pc_error(int number,char *message,char *filename,int firstline,int lastline,va_list argptr) { #if PAWN_CELL_SIZE==32 static char *prefix[3]={ "error", "fatal error", "warning" }; if (number!=0) { char *pre; pre=prefix[number/100]; if (firstline>=0) pc_printf("%s(%d -- %d) : %s %03d: ",filename,firstline,lastline,pre,number); else pc_printf("%s(%d) : %s %03d: ",filename,lastline,pre,number); } /* if */ vprintf(message,argptr); #endif return 0; } typedef struct src_file_s { FILE *fp; // Set if writing. char *buffer; // IO buffer. char *pos; // IO position. char *end; // End of buffer. size_t maxlength; // Maximum length of the writable buffer. } src_file_t; /* pc_opensrc() * Opens a source file (or include file) for reading. The "file" does not have * to be a physical file, one might compile from memory. * filename the name of the "file" to read from * Return: * The function must return a pointer, which is used as a "magic cookie" to * all I/O functions. When failing to open the file for reading, the * function must return NULL. * Note: * Several "source files" may be open at the same time. Specifically, one * file can be open for reading and another for writing. */ void *pc_opensrc(char *filename) { FILE *fp = NULL; long length; src_file_t *src = NULL; #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined DARWIN struct stat fileInfo; if (stat(filename, &fileInfo) != 0) { return NULL; } if (S_ISDIR(fileInfo.st_mode)) { return NULL; } #endif if ((fp = fopen(filename, "rb")) == NULL) return NULL; if (fseek(fp, 0, SEEK_END) == -1) goto err; if ((length = ftell(fp)) == -1) goto err; if (fseek(fp, 0, SEEK_SET) == -1) goto err; if ((src = (src_file_t *)calloc(1, sizeof(src_file_t))) == NULL) goto err; if ((src->buffer = (char *)calloc(length, sizeof(char))) == NULL) goto err; if (fread(src->buffer, length, 1, fp) != 1) goto err; src->pos = src->buffer; src->end = src->buffer + length; return src; err: pc_closesrc(src); fclose(fp); return NULL; } /* pc_createsrc() * Creates/overwrites a source file for writing. The "file" does not have * to be a physical file, one might compile from memory. * filename the name of the "file" to create * Return: * The function must return a pointer, which is used as a "magic cookie" to * all I/O functions. When failing to open the file for reading, the * function must return NULL. * Note: * Several "source files" may be open at the same time. Specifically, one * file can be open for reading and another for writing. */ void *pc_createsrc(char *filename) { src_file_t *src = (src_file_t *)calloc(1, sizeof(src_file_t)); if (!src) return NULL; if ((src->fp = fopen(filename, "wt")) == NULL) { pc_closesrc(src); return NULL; } src->maxlength = 1024; if ((src->buffer = (char *)calloc(1, src->maxlength)) == NULL) { pc_closesrc(src); return NULL; } src->pos = src->buffer; src->end = src->buffer; return src; } /* pc_closesrc() * Closes a source file (or include file). The "handle" parameter has the * value that pc_opensrc() returned in an earlier call. */ void pc_closesrc(void *handle) { src_file_t *src = (src_file_t *)handle; if (!src) return; if (src->fp) { fwrite(src->buffer, src->pos - src->buffer, 1, src->fp); fclose(src->fp); } free(src->buffer); free(src); } /* pc_resetsrc() * "position" may only hold a pointer that was previously obtained from * pc_getpossrc() */ void pc_resetsrc(void *handle,void *position) { src_file_t *src = (src_file_t *)handle; ptrdiff_t pos = (ptrdiff_t)position; assert(!src->fp); assert(pos >= 0 && src->buffer + pos <= src->end); src->pos = src->buffer + pos; } /* pc_readsrc() * Reads a single line from the source file (or up to a maximum number of * characters if the line in the input file is too long). */ char *pc_readsrc(void *handle,unsigned char *target,int maxchars) { src_file_t *src = (src_file_t *)handle; char *outptr = (char *)target; char *outend = outptr + maxchars; assert(!src->fp); if (src->pos == src->end) return NULL; while (outptr < outend && src->pos < src->end) { char c = *src->pos++; *outptr++ = c; if (c == '\n') break; if (c == '\r') { // Handle CRLF. if (src->pos < src->end && *src->pos == '\n') { src->pos++; if (outptr < outend) *outptr++ = '\n'; } break; } } // Caller passes in a buffer of size >= maxchars+1. *outptr = '\0'; return (char *)target; } /* pc_writesrc() * Writes to to the source file. There is no automatic line ending; to end a * line, write a "\n". */ int pc_writesrc(void *handle,unsigned char *source) { char *str = (char *)source; size_t len = strlen(str); src_file_t *src = (src_file_t *)handle; assert(src->fp && src->maxlength); if (src->pos + len > src->end) { char *newbuf; size_t newmax = src->maxlength; size_t newlen = (src->pos - src->buffer) + len; while (newmax < newlen) { // Grow by 1.5X newmax += newmax + newmax / 2; if (newmax < src->maxlength) abort(); } newbuf = (char *)realloc(src->buffer, newmax); if (!newbuf) abort(); src->pos = newbuf + (src->pos - src->buffer); src->end = newbuf + newmax; src->buffer = newbuf; src->maxlength = newmax; } strcpy(src->pos, str); src->pos += len; return 0; } void *pc_getpossrc(void *handle) { src_file_t *src = (src_file_t *)handle; assert(!src->fp); return (void *)(ptrdiff_t)(src->pos - src->buffer); } int pc_eofsrc(void *handle) { src_file_t *src = (src_file_t *)handle; assert(!src->fp); return src->pos == src->end; } /* should return a pointer, which is used as a "magic cookie" to all I/O * functions; return NULL for failure */ void *pc_openasm(char *filename) { #if defined __MSDOS__ || defined SC_LIGHT return fopen(filename,"w+t"); #else return mfcreate(filename); #endif } void pc_closeasm(void *handle, int deletefile) { #if defined __MSDOS__ || defined SC_LIGHT if (handle!=NULL) fclose((FILE*)handle); if (deletefile) remove(outfname); #else if (handle!=NULL) { if (!deletefile) mfdump((MEMFILE*)handle); mfclose((MEMFILE*)handle); } /* if */ #endif } void pc_resetasm(void *handle) { assert(handle!=NULL); #if defined __MSDOS__ || defined SC_LIGHT fflush((FILE*)handle); fseek((FILE*)handle,0,SEEK_SET); #else mfseek((MEMFILE*)handle,0,SEEK_SET); #endif } int pc_writeasm(void *handle,char *string) { #if defined __MSDOS__ || defined SC_LIGHT return fputs(string,(FILE*)handle) >= 0; #else return mfputs((MEMFILE*)handle,string); #endif } char *pc_readasm(void *handle, char *string, int maxchars) { #if defined __MSDOS__ || defined SC_LIGHT return fgets(string,maxchars,(FILE*)handle); #else return mfgets((MEMFILE*)handle,string,maxchars); #endif } /* Should return a pointer, which is used as a "magic cookie" to all I/O * functions; return NULL for failure. */ void *pc_openbin(char *filename) { return fopen(filename,"wb"); } void pc_closebin(void *handle,int deletefile) { fclose((FILE*)handle); if (deletefile) remove(binfname); } /* pc_resetbin() * Can seek to any location in the file. * The offset is always from the start of the file. */ void pc_resetbin(void *handle,long offset) { fflush((FILE*)handle); fseek((FILE*)handle,offset,SEEK_SET); } int pc_writebin(void *handle,void *buffer,int size) { return (int)fwrite(buffer,1,size,(FILE*)handle) == size; } long pc_lengthbin(void *handle) { return ftell((FILE*)handle); }