// vim: set ts=4 sw=4 tw=99 noet: // // AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). // Copyright (C) The AMX Mod X Development Team. // // This software is licensed under the GNU General Public License, version 3 or higher. // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://alliedmods.net/amxmodx-license // intptr_t #ifdef _MSC_VER typedef int intptr_t; #define _INTPTR_T_DEFINED #endif #ifdef __GNUC__ #include #include #include #include #endif // header file for unlink() #if defined(__linux__) || defined(__APPLE__) #include #else #define WINDOWS_LEAN_AND_MEAN #include #include #endif #include "amxmodx.h" CVector FileList; class AutoFilePtr { FILE *m_FP; public: AutoFilePtr(FILE *fp) : m_FP(fp) {} ~AutoFilePtr() { if (m_FP) fclose(m_FP); } operator FILE* () { return m_FP; } }; enum FileTimeType { FileTime_LastAccess = 0, /* Last access (not available on FAT) */ FileTime_Created = 1, /* Creation (not available on FAT) */ FileTime_LastChange = 2, /* Last modification */ }; static cell AMX_NATIVE_CALL read_dir(AMX *amx, cell *params) { #ifdef __GNUC__ int a; struct dirent *ep; DIR *dp; char* dirname = build_pathname("%s", get_amxstring(amx, params[1], 0, a)); a = params[2]; if ((dp = opendir (dirname)) == NULL) return 0; seekdir(dp, a); if ((ep = readdir (dp)) != NULL) { cell *length = get_amxaddr(amx, params[5]); *length = set_amxstring(amx, params[3], ep->d_name, params[4]); a = telldir(dp); } else a = 0; closedir (dp); return a; #else int tmp; char *dirname = build_pathname("%s/*", get_amxstring(amx, params[1], 0, tmp)); tmp = params[2]; _finddata_t fd; intptr_t handle = _findfirst(dirname, &fd); if (handle < 0) return 0; ++tmp; for (int i = 0; i < tmp; ++i) { if (_findnext(handle, &fd) < 0) { tmp = 0; break; } } // current data in fd cell *length = get_amxaddr(amx, params[5]); // pointer to the outLen parameter *length = set_amxstring(amx, params[3], fd.name, params[4]); // set output and outLen parameters _findclose(handle); return tmp; #endif // __GNUC__ } static cell AMX_NATIVE_CALL read_file(AMX *amx, cell *params) /* 5 param */ { int iLen; char* szFile = get_amxstring(amx, params[1], 0, iLen); FILE *fp; if ((fp =fopen(build_pathname("%s", szFile), "r")) == NULL) { LogError(amx, AMX_ERR_NATIVE, "Couldn't read file \"%s\"", szFile); return 0; } char buffor[1024]; int i = 0, iLine = params[2]; while ((i <= iLine) && fgets(buffor, 1023, fp)) i++; fclose(fp); if (i > iLine) { int len = strlen(buffor); if (buffor[len - 1] == '\n') buffor[--len] = 0; if (buffor[len - 1] == '\r') buffor[--len] = 0; cell *length = get_amxaddr(amx, params[5]); *length = set_amxstring_utf8(amx, params[3], buffor, len, params[4] + 1); // + EOS return i; } return 0; } static cell AMX_NATIVE_CALL write_file(AMX *amx, cell *params) /* 3 param */ { int i; char* sFile = build_pathname("%s", get_amxstring(amx, params[1], 0, i)); char* sText = get_amxstring(amx, params[2], 0, i); FILE* pFile; int iLine = params[3]; // apending to the end if (iLine < 0) { if ((pFile = fopen(sFile, "a")) == NULL) { LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", sFile); return 0; } fputs(sText, pFile); fputc('\n', pFile); fclose(pFile); return 1; } // creating a new file with a line in a middle if ((pFile = fopen(sFile, "r")) == NULL) { if ((pFile = fopen(sFile, "w")) == NULL) { LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", sFile); return 0; } for (i = 0; i < iLine; ++i) fputc('\n', pFile); fputs(sText, pFile); fputc('\n', pFile); fclose(pFile); return 1; } // adding a new line in a middle of already existing file FILE* pTemp; char buffor[2048]; if ((pTemp = tmpfile()) == NULL) { LogError(amx, AMX_ERR_NATIVE, "Couldn't create temp file"); return 0; } for (i = 0; ; ++i) { if (i == iLine) { fgets(buffor, 2047, pFile); fputs(sText, pTemp); fputc('\n', pTemp); } else if (fgets(buffor, 2047, pFile)) { fputs(buffor, pTemp); } else if (i < iLine) { fputc('\n', pTemp); } else break; } fclose(pFile); rewind(pTemp); // now rewrite because file can be now smaller... if ((pFile = fopen(sFile, "w")) == NULL) { LogError(amx, AMX_ERR_NATIVE, "Couldn't write file \"%s\"", sFile); return 0; } while (fgets(buffor, 2047, pTemp)) fputs(buffor, pFile); fclose(pTemp); fclose(pFile); return 1; } static cell AMX_NATIVE_CALL delete_file(AMX *amx, cell *params) /* 1 param */ { int iLen; char* sFile = get_amxstring(amx, params[1], 0, iLen); return (unlink(build_pathname("%s", sFile)) ? 0 : 1); } static cell AMX_NATIVE_CALL file_exists(AMX *amx, cell *params) /* 1 param */ { int iLen; char *sFile = get_amxstring(amx, params[1], 0, iLen); char *file = build_pathname("%s", sFile); #if defined WIN32 || defined _WIN32 DWORD attr = GetFileAttributes(file); if (attr == INVALID_FILE_ATTRIBUTES) return 0; if (attr == FILE_ATTRIBUTE_DIRECTORY) return 0; return 1; #else struct stat s; if (stat(file, &s) != 0) return 0; if (S_ISDIR(s.st_mode)) return 0; return 1; #endif } static cell AMX_NATIVE_CALL dir_exists(AMX *amx, cell *params) /* 1 param */ { int iLen; char *sFile = get_amxstring(amx, params[1], 0, iLen); char *file = build_pathname("%s", sFile); return DirExists(file) ? 1 : 0; } static cell AMX_NATIVE_CALL file_size(AMX *amx, cell *params) /* 1 param */ { int iLen; char* sFile = get_amxstring(amx, params[1], 0, iLen); AutoFilePtr fp(fopen(build_pathname("%s", sFile), "r")); if (fp != NULL) { if (params[0] < 2 || params[2] == 0) { fseek(fp, 0, SEEK_END); int size = ftell(fp); return size; } else if (params[2] == 1) { int a = 0,lines = 0; while (a != EOF) { ++lines; while ((a = fgetc(fp)) != '\n' && a != EOF); } //int a, b = '\n'; //while( (a = fgetc(fp)) != EOF ){ // if ( a == '\n') // ++lines; // b = a; //} //if ( b != '\n' ) // ++lines; return lines; } else if (params[2] == 2) { fseek(fp, -1, SEEK_END); if (fgetc(fp) == '\n') return 1; return 0; } } return -1; } static cell AMX_NATIVE_CALL amx_fopen(AMX *amx, cell *params) { int len; char *file = build_pathname("%s", get_amxstring(amx, params[1], 1, len)); char *flags = get_amxstring(amx, params[2], 0, len); FILE *fp = fopen(file, flags); return (cell)fp; } static cell AMX_NATIVE_CALL amx_fwrite_blocks(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; cell *addr = get_amxaddr(amx, params[2]); size_t blocks = params[3]; size_t btmp = blocks; cell mode = params[4]; switch (mode) { case 1: { char *a = new char[blocks]; char *ptr = a; while (btmp--) *ptr++ = static_cast(*addr++); size_t res = fwrite(a, sizeof(char), blocks, fp); delete [] a; return res; } case 2: { short *a = new short[blocks]; short *ptr = a; while (btmp--) *ptr++ = static_cast(*addr++); size_t res = fwrite(a, sizeof(short), blocks, fp); delete [] a; return res; } case 4: { int *a = new int[blocks]; int *ptr = a; while (btmp--) *ptr++ = static_cast(*addr++); size_t res = fwrite(a, sizeof(int), blocks, fp); delete [] a; return res; } } return 0; } static cell AMX_NATIVE_CALL amx_fwrite(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; size_t mode = params[3]; switch (mode) { case 1: { char a = static_cast(params[2]); return fwrite(&a, sizeof(char), 1, fp); } case 2: { short b = static_cast(params[2]); return fwrite(&b, sizeof(short), 1, fp); } case 4: { int c = static_cast(params[2]); return fwrite(&c, sizeof(int), 1, fp); } } return 0; } static cell AMX_NATIVE_CALL amx_fwrite_raw(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; cell *addr = get_amxaddr(amx, params[2]); return fwrite(addr, params[3], params[4], fp); } static cell AMX_NATIVE_CALL amx_fread_raw(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; cell *addr = get_amxaddr(amx, params[2]); size_t size = static_cast(params[3]); size_t blocks = static_cast(params[4]); return fread(addr, size, blocks, fp); } static cell AMX_NATIVE_CALL amx_fread(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; cell *addr = get_amxaddr(amx, params[2]); switch (params[3]) { case 1: //char { char a; size_t res = fread(&a, sizeof(char), 1, fp); *addr = static_cast(a); return res; } case 2: //short { short a; size_t res = fread(&a, sizeof(short), 1, fp); *addr = static_cast(a); return res; } case 4: //int default: { int a; size_t res = fread(&a, sizeof(int), 1, fp); *addr = static_cast(a); return res; } } return 0; } static cell AMX_NATIVE_CALL amx_fread_blocks(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; cell *addr = get_amxaddr(amx, params[2]); size_t blocks = params[3]; switch (params[4]) { case 1: //char { char *a = new char[blocks]; char *ptr = a; size_t res = fread(a, sizeof(char), blocks, fp); while (blocks--) *addr++ = static_cast(*ptr++); delete [] a; return res; } case 2: //short { short *a = new short[blocks]; short *ptr = a; size_t res = fread(a, sizeof(short), blocks, fp); while (blocks--) *addr++ = static_cast(*ptr++); delete [] a; return res; } case 4: //int default: { int *a = new int[blocks]; int *ptr = a; size_t res = fread(a, sizeof(int), blocks, fp); while (blocks--) *addr++ = static_cast(*ptr++); delete [] a; return res; } } return 0; } static cell AMX_NATIVE_CALL amx_fputs(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; int len; char *str = get_amxstring(amx, params[2], 0, len); return fputs(str, fp); } static cell AMX_NATIVE_CALL amx_fgets(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; static char buffer[4096]; buffer[0] = '\0'; fgets(buffer, sizeof(buffer)-1, fp); return set_amxstring_utf8(amx, params[2], buffer, strlen(buffer), params[3] + 1); // + EOS } static cell AMX_NATIVE_CALL amx_fseek(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; return fseek(fp, params[2], params[3]); } static cell AMX_NATIVE_CALL amx_ftell(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; return ftell(fp); } static cell AMX_NATIVE_CALL amx_fprintf(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; int len; char *str = format_amxstring(amx, params, 2, len); return fprintf(fp, "%s", str); } static cell AMX_NATIVE_CALL amx_feof(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 1; return feof(fp); } static cell AMX_NATIVE_CALL amx_fclose(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 1; fclose(fp); return 1; } static cell AMX_NATIVE_CALL amx_filesize(AMX *amx, cell *params) { int len; char *file = build_pathname("%s", format_amxstring(amx, params, 1, len)); long size; AutoFilePtr fp(fopen(file, "rb")); if (fp) { fseek(fp, 0, SEEK_END); size = ftell(fp); return size; } return -1; } static cell AMX_NATIVE_CALL amx_build_pathname(AMX *amx, cell *params) { int len; char *szPath = get_amxstring(amx, params[1], 0, len); return set_amxstring(amx, params[2], build_pathname("%s", szPath), params[3]); } static cell AMX_NATIVE_CALL amx_open_dir(AMX *amx, cell *params) { int len; char *path = get_amxstring(amx, params[1], 0, len); #if defined WIN32 || defined _WIN32 char *dirname = build_pathname("%s\\*", path); WIN32_FIND_DATA fd; HANDLE hFile = FindFirstFile(dirname, &fd); if (hFile == INVALID_HANDLE_VALUE) return 0; set_amxstring(amx, params[2], fd.cFileName, params[3]); return (DWORD)hFile; #else char *dirname = build_pathname("%s", path); DIR *dp = opendir(dirname); if (!dp) return 0; struct dirent *ep = readdir(dp); if (!ep) { closedir(dp); return 0; } set_amxstring(amx, params[2], ep->d_name, params[3]); return (cell)dp; #endif } static cell AMX_NATIVE_CALL amx_close_dir(AMX *amx, cell *params) { #if defined WIN32 || defined _WIN32 HANDLE hFile = (HANDLE)((DWORD)params[1]); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) return 0; FindClose(hFile); return 1; #else DIR *dp = (DIR *)params[1]; if (!dp) return 0; closedir(dp); return 1; #endif } static cell AMX_NATIVE_CALL amx_get_dir(AMX *amx, cell *params) { #if defined WIN32 || defined _WIN32 HANDLE hFile = (HANDLE)((DWORD)params[1]); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) return 0; WIN32_FIND_DATA fd; if (!FindNextFile(hFile, &fd)) return 0; set_amxstring(amx, params[2], fd.cFileName, params[3]); return 1; #else DIR *dp = (DIR *)params[1]; if (!dp) return 0; struct dirent *ep = readdir(dp); if (!ep) return 0; set_amxstring(amx, params[2], ep->d_name, params[3]); return 1; #endif } //native fgetc( file ); static cell AMX_NATIVE_CALL amx_fgetc(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; return fgetc(fp); } //native fputc( file, data ); static cell AMX_NATIVE_CALL amx_fputc(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; return fputc(static_cast(params[2]), fp); } //native ungetc( file, data ); static cell AMX_NATIVE_CALL amx_ungetc(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; if (!fp) return 0; return ungetc(static_cast(params[2]), fp); } #if defined(__linux__) || defined(__APPLE__) #define _rmdir rmdir #endif static cell AMX_NATIVE_CALL amx_rmdir(AMX *amx, cell *params) { int len; char* sFile = build_pathname("%s", get_amxstring(amx, params[1], 0, len)); if (_rmdir(sFile) != 0) return 0; return 1; } static cell AMX_NATIVE_CALL amx_rename(AMX *amx, cell *params) { int len; char f_old_r[260]; char f_new_r[260]; char *fold = get_amxstring(amx, params[1], 0, len); char *fnew = get_amxstring(amx, params[2], 1, len); if (params[0] / sizeof(cell) == 3 && params[3]) { build_pathname_r(f_old_r, sizeof(f_old_r)-1, "%s", fold); build_pathname_r(f_new_r, sizeof(f_new_r)-1, "%s", fnew); } else { UTIL_Format(f_old_r, sizeof(f_old_r)-1, "%s", fold); UTIL_Format(f_new_r, sizeof(f_new_r)-1, "%s", fnew); } #if defined(__linux__) || defined(__APPLE__) return (rename(f_old_r, f_new_r) == 0); #elif defined WIN32 return MoveFileA(f_old_r, f_new_r); #endif } static cell LoadFileForMe(AMX *amx, cell *params) { int len; char *file = get_amxstring(amx, params[1], 0, len); char path[256]; build_pathname_r(path, sizeof(path), "%s", file); byte *addr = LOAD_FILE_FOR_ME(path, &len); if (addr == NULL) { return -1; } cell *buffer = get_amxaddr(amx, params[2]); cell maxlength = params[3]; cell *bytes_avail = get_amxaddr(amx, params[4]); *bytes_avail = len; cell count; for (count = 0; count < len && count < maxlength; count++) { buffer[count] = addr[count]; } FREE_FILE(addr); return count; } static cell AMX_NATIVE_CALL amx_fflush(AMX *amx, cell *params) { FILE *fp = (FILE *)params[1]; return fflush(fp); } static cell AMX_NATIVE_CALL GetFileTime(AMX *amx, cell *params) { int len; char *file = get_amxstring(amx, params[1], 0, len); char path[256]; build_pathname_r(path, sizeof(path), "%s", file); #if defined(WIN32) struct _stat s; if (_stat(path, &s) != 0) #elif defined(__linux__) || defined(__APPLE__) struct stat s; if (stat(path, &s) != 0) #endif { return -1; } time_t time_val = -1; switch( params[2] ) { case FileTime_LastAccess : time_val = s.st_atime; break; case FileTime_Created : time_val = s.st_ctime; break; case FileTime_LastChange : time_val = s.st_mtime; break; } return (cell)time_val; } AMX_NATIVE_INFO file_Natives[] = { {"delete_file", delete_file}, {"file_exists", file_exists}, {"file_size", file_size}, {"read_dir", read_dir}, {"read_file", read_file}, {"write_file", write_file}, //new, sane file natives {"fopen", amx_fopen}, {"fclose", amx_fclose}, {"fread", amx_fread}, {"fread_blocks", amx_fread_blocks}, {"fread_raw", amx_fread_raw}, {"fwrite", amx_fwrite}, {"fwrite_blocks", amx_fwrite_blocks}, {"fwrite_raw", amx_fwrite_raw}, {"feof", amx_feof}, {"fprintf", amx_fprintf}, {"fgets", amx_fgets}, {"fseek", amx_fseek}, {"ftell", amx_ftell}, {"filesize", amx_filesize}, {"unlink", delete_file}, {"build_pathname", amx_build_pathname}, {"dir_exists", dir_exists}, {"open_dir", amx_open_dir}, {"close_dir", amx_close_dir}, {"next_file", amx_get_dir}, {"fgetc", amx_fgetc}, {"fputc", amx_fputc}, {"fungetc", amx_ungetc}, {"rmdir", amx_rmdir}, {"fputs", amx_fputs}, {"rename_file", amx_rename}, {"LoadFileForMe", LoadFileForMe}, {"fflush", amx_fflush}, {"GetFileTime", GetFileTime}, {NULL, NULL} };