cfad47cfa3/t3compiler/src/osportable3.cc
Commiter: Nikos Chantziaras
Author: Nikos Chantziaras
Revision: cfad47cfa3
File Size: 8.66 KB
(June 01, 2009 20:54 UTC) Almost 3 years ago
Initial commit.
/* This file implements some of the functions described in
* tads2/osifc.h. Only functions needed by the TADS 3 compiler are
* implemented here.
*
* The functions are "portable"; they don't make use of curses/ncurses.
*/
#include "common.h"
#include <stdio.h>
#include <string.h>
extern "C" {
#include <sys/stat.h>
#include <dirent.h>
}
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#include "os.h"
/* Set the game title.
*
* Does nothing in the compiler. This should actually be implemented in
* tads3/os_stdio.cpp, but for some reason it's not.
*/
void
os_set_title( const char* )
{
}
/* Get the modification time for a file.
*/
int
os_get_file_mod_time( os_file_time_t* t, const char* fname )
{
struct stat inf;
if (stat(fname, &inf) != 0) return 1;
t->t = inf.st_mtime;
return 0;
}
/* Compare two file time values.
*/
int
os_cmp_file_times( const os_file_time_t* a, const os_file_time_t* b )
{
if (a->t < b->t) return -1;
if (a->t == b->t) return 0;
return 1;
}
/* Install/uninstall the break handler.
*
* I don't think we need a break handler.
*/
void
os_instbrk( int )
{
}
/* We implement the file searching routines using <glob.h>. It's not
* available on all systems though, so we provide dummy fallbacks that
* do nothing if <glob.h> doesn't exist.
*/
#ifdef HAVE_GLOB
/* Search context structure.
*/
struct oss_find_ctx_t
{
glob_t* pglob;
// Index of current filename in pglob->gl_pathv.
size_t current;
// Original search path prefix (we'll allocate more to fit the
// string).
char path[1];
};
/* Service routine for searching - build the full output path name.
*/
static void
oss_build_outpathbuf( char* outpathbuf, size_t outpathbufsiz, const char* path,
const char* fname )
{
// If there's a full path buffer, build the full path.
if (outpathbuf != 0) {
size_t lp;
size_t lf;
// Copy the path prefix.
lp = strlen(path);
if (lp > outpathbufsiz - 1) {
lp = outpathbufsiz - 1;
}
memcpy(outpathbuf, path, lp);
// Add the filename if there's any room.
lf = strlen(fname);
if (lf > outpathbufsiz - lp - 1) {
lf = outpathbufsiz - lp - 1;
}
memcpy(outpathbuf + lp, fname, lf);
// Null-terminate the result.
outpathbuf[lp + lf] = '\0';
}
}
/* Find the first file matching a given pattern.
*/
void*
os_find_first_file( const char* dir, const char* pattern, char* outbuf, size_t outbufsiz,
int* isdir, char* outpathbuf, size_t outpathbufsiz)
{
char realpat[OSFNMAX];
size_t l;
size_t path_len;
const char* lastsep;
const char* p;
struct oss_find_ctx_t* ctx = 0;
strcpy(realpat, dir);
if ((l = strlen(realpat)) != 0 && realpat[l - 1] != '/') {
realpat[l++] = '/';
}
if (pattern == 0) {
strcpy(realpat + l, "*");
} else {
strcpy(realpat + l, pattern);
}
// Find the last separator in the original path.
for (p = realpat, lastsep = 0 ; *p != '\0' ; ++p) {
// If this is a separator, remember it.
if (*p == '/') lastsep = p;
}
// If we found a separator, the path prefix is everything up to
// and including the separator; otherwise, there's no path
// prefix.
if (lastsep != 0) {
// The length of the path includes the separator.
path_len = lastsep + 1 - realpat;
} else {
// There's no path prefix - everything is in the
// current directory.
path_len = 0;
}
// Allocate a context.
ctx = static_cast(struct oss_find_ctx_t*)(malloc(sizeof(struct oss_find_ctx_t) + path_len));
ctx->pglob = static_cast(glob_t *)(malloc(sizeof(glob_t)));
ctx->current = -1;
// Copy the path to the context. we may need it later to build
// a full path.
memcpy(ctx->path, realpat, path_len);
ctx->path[path_len] = '\0';
// Problem: before calling glob() we need to escape all [] in
// realpat. Count them first.
int nbracket = 0;
for (p = realpat; *p != '\0' ; ++p) {
if (*p == '[' || *p == ']') ++nbracket;
}
// Allocate string for escaped pattern.
char* escaped_realpat = static_cast(char*)(malloc(strlen(realpat) + nbracket + 1));
// Copy pattern to new string, escaping all [ and ] with \.
char* c = realpat;
char* k = escaped_realpat;
while (*c != '\0') {
if (*c == '[' || *c == ']') {
*k++ = '\\';
}
*k++ = *c++;
}
*k++ = '\0';
int res = glob(escaped_realpat, GLOB_ERR | GLOB_MARK, NULL, ctx->pglob);
if (res != 0) {
// We don't really care what kind of error occured.
// Just free the resources and return error. Note that
// "no files found" is an error.
if (ctx->pglob != 0) {
globfree(ctx->pglob);
free(ctx->pglob);
}
if (ctx != 0) {
free(ctx);
}
free(escaped_realpat);
*isdir = 0;
return 0;
}
// If we get there, there was a match. set current index for
// os_find_next().
ctx->current = 0;
// glob() returns filename with directory, but we need just the
// basename. Copy first filename into the caller's buffer.
char* ptr = &ctx->pglob->gl_pathv[0][path_len];
l = strlen(ptr);
if (l > outbufsiz - 1) {
l = outbufsiz - 1;
}
memcpy(outbuf, ptr, l);
outbuf[l] = '\0';
// Build the full path, if desired.
oss_build_outpathbuf(outpathbuf, outpathbufsiz, ctx->path, ptr);
// Return the directory indication.
*isdir = (ptr[l-1] == '/') ? true : false;
free(escaped_realpat);
return ctx;
}
/* Find the next matching file, continuing a search started with
* os_find_first_file().
*/
void*
os_find_next_file( void* ctx0, char* outbuf, size_t outbufsiz, int* isdir, char* outpathbuf,
size_t outpathbufsiz )
{
struct oss_find_ctx_t* ctx = static_cast(struct oss_find_ctx_t*)(ctx0);
size_t l;
// If the search has already ended, do nothing.
if (ctx == 0) return 0;
if (++ctx->current > ctx->pglob->gl_pathc - 1) {
// No more files - delete the context and give up.
globfree(ctx->pglob);
free(ctx->pglob);
free(ctx);
// Indicate that the search is finished.
return 0;
}
// Return the name. See comments in os_find_first_file().
l = strlen(ctx->path);
char* ptr = &ctx->pglob->gl_pathv[ctx->current][l];
l = strlen(ptr);
if (l > outbufsiz - 1) {
l = outbufsiz - 1;
}
memcpy(outbuf, ptr, l);
outbuf[l] = '\0';
// Return the directory indication.
*isdir = (ptr[l-1] == '/') ? true : false;
// Build the full path, if desired.
oss_build_outpathbuf(outpathbuf, outpathbufsiz, ctx->path, ptr);
// Indicate that the search was successful by returning the
// non-null context pointer -- the context has been updated for
// the new position in the search, so we just return the same
// context structure that we've been using all along.
return ctx;
}
/* Cancel a search.
*/
void
os_find_close( void* ctx0 )
{
struct oss_find_ctx_t* ctx = static_cast(struct oss_find_ctx_t*)(ctx0);
// If the search was already cancelled, do nothing.
if (ctx == 0) return;
// Delete the search context.
if (ctx->pglob != 0) {
globfree(ctx->pglob);
free(ctx->pglob);
}
free(ctx);
}
#else
/* <glob.h> isn't available. We just provide do-nothing dummies.
*/
void*
os_find_first_file( const char* /*dir*/, const char* /*pattern*/, char* /*outbuf*/, size_t /*outbufsiz*/,
int* /*isdir*/, char* /*outpathbuf*/, size_t /*outpathbufsiz*/ )
{
return 0;
}
void*
os_find_next_file( void* /*ctx*/, char* /*outbuf*/, size_t /*outbufsiz*/, int* /*isdir*/,
char* /*outpathbuf*/, size_t /*outpathbufsiz*/ )
{
return 0;
}
void
os_find_close( void* /*ctx*/ )
{
}
#endif // HAVE_GLOB
/* Determine if the given filename refers to a special file.
*
* tads2/osnoui.c defines its own version when MSDOS is defined.
*/
#ifndef MSDOS
os_specfile_t
os_is_special_file( const char* fname )
{
// We also check for "./" and "../" instead of just "." and
// "..". (We use OSPATHCHAR instead of '/' though.)
const char selfWithSep[3] = {'.', OSPATHCHAR, '\0'};
const char parentWithSep[4] = {'.', '.', OSPATHCHAR, '\0'};
if ((strcmp(fname, ".") == 0) or (strcmp(fname, selfWithSep) == 0)) return OS_SPECFILE_SELF;
if ((strcmp(fname, "..") == 0) or (strcmp(fname, parentWithSep) == 0)) return OS_SPECFILE_PARENT;
return OS_SPECFILE_NONE;
}
#endif
/* Initialize.
*/
int
os_init( int*, char**, const char*, char*, int )
{
return 0;
}
/* Uninitialize.
*/
void
os_uninit( void )
{
}
/* =====================================================================
* These functions are currently not used by the compiler. If the
* linker barks, we must implement them.
*/
/* Get the creation time for a file.
*/
/*
int
os_get_file_cre_time( os_file_time_t* t, const char* fname )
{
}
*/
/* Get the access time for a file.
*/
/*
int
os_get_file_acc_time( os_file_time_t* t, const char* fname )
{
}
*/
/* Switch to a new working directory.
*/
/*
oid
os_set_pwd( const char* dir )
{
}
*/
/* Switch the working directory to the directory containing the given
* file.
*/
/*
void
os_set_pwd_file( const char* filename )
{
}
*/ |