#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#include "config-msvc.h"
#else
#include "config.h"
#endif
#include <spatialite/sqlite.h>
#include <spatialite/gaiaaux.h>
#include <spatialite_private.h>
#ifdef _WIN32
#define strcasecmp _stricmp
#endif
#if defined(_WIN32) && !defined(__MINGW32__)
#define FRMT64 "%I64d"
#else
#define FRMT64 "%lld"
#endif
GAIAAUX_DECLARE int
gaiaIllegalSqlName (const char *name)
{
int i;
int len;
if (!name)
return 1;
len = strlen (name);
if (len == 0)
return 1;
for (i = 0; i < len; i++)
{
if (name[i] >= 'a' && name[i] <= 'z')
continue;
if (name[i] >= 'A' && name[i] <= 'Z')
continue;
if (name[i] >= '0' && name[i] <= '9')
continue;
if (name[i] == '_')
continue;
return 1;
}
if (name[0] >= 'a' && name[0] <= 'z')
return 0;
if (name[0] >= 'A' && name[0] <= 'Z')
return 0;
return 1;
}
GAIAAUX_DECLARE int
gaiaIsReservedSqliteName (const char *name)
{
char *reserved[] = {
"ALL",
"ALTER",
"AND",
"AS",
"AUTOINCREMENT",
"BETWEEN",
"BLOB",
"BY",
"CASE",
"CHECK",
"COLLATE",
"COMMIT",
"CONSTRAINT",
"CREATE",
"CROSS",
"DATE",
"DATETIME",
"DEFAULT",
"DEFERRABLE",
"DELETE",
"DISTINCT",
"DOUBLE",
"DROP",
"ELSE",
"ESCAPE",
"EXCEPT",
"FOREIGN",
"FROM",
"FULL",
"GLOB",
"GROUP",
"HAVING",
"IN",
"INDEX",
"INNER",
"INSERT",
"INTEGER",
"INTERSECT",
"INTO",
"IS",
"ISNULL",
"JOIN",
"KEY",
"LEFT",
"LIKE",
"LIMIT",
"MATCH",
"NATURAL",
"NOT",
"NOTNULL",
"NULL",
"ON",
"OR",
"ORDER",
"OUTER",
"PRAGMA",
"PRIMARY",
"REFERENCES",
"REPLACE",
"RIGHT",
"ROLLBACK",
"SELECT",
"SET",
"TABLE",
"TEMP",
"TEMPORARY",
"THEN",
"TEXT",
"TIMESTAMP",
"TO",
"TRANSACTION",
"UNION",
"UNIQUE",
"UPDATE",
"USING",
"VALUES",
"VIEW",
"WHEN",
"WHERE",
NULL
};
char **pw = reserved;
while (*pw != NULL)
{
if (strcasecmp (name, *pw) == 0)
return 1;
pw++;
}
return 0;
}
GAIAAUX_DECLARE int
gaiaIsReservedSqlName (const char *name)
{
char *reserved[] = {
"ABSOLUTE",
"ACTION",
"ADD",
"AFTER",
"ALL",
"ALLOCATE",
"ALTER",
"AND",
"ANY",
"ARE",
"ARRAY",
"AS",
"ASC",
"ASENSITIVE",
"ASSERTION",
"ASYMMETRIC",
"AT",
"ATOMIC",
"AUTHORIZATION",
"AVG",
"BEFORE",
"BEGIN",
"BETWEEN",
"BIGINT",
"BINARY",
"BIT",
"BIT_LENGTH",
"BLOB",
"BOOLEAN",
"BOTH",
"BREADTH",
"BY",
"CALL",
"CALLED",
"CASCADE",
"CASCADED",
"CASE",
"CAST",
"CATALOG",
"CHAR",
"CHARACTER",
"CHARACTER_LENGTH",
"CHAR_LENGTH",
"CHECK",
"CLOB",
"CLOSE",
"COALESCE",
"COLLATE",
"COLLATION",
"COLUMN",
"COMMIT",
"CONDITION",
"CONNECT",
"CONNECTION",
"CONSTRAINT",
"CONSTRAINTS",
"CONSTRUCTOR",
"CONTAINS",
"CONTINUE",
"CONVERT",
"CORRESPONDING",
"COUNT",
"CREATE",
"CROSS",
"CUBE",
"CURRENT",
"CURRENT_DATE",
"CURRENT_DEFAULT_TRANSFORM_GROUP",
"CURRENT_PATH",
"CURRENT_ROLE",
"CURRENT_TIME",
"CURRENT_TIMESTAMP",
"CURRENT_TRANSFORM_GROUP_FOR_TYPE",
"CURRENT_USER",
"CURSOR",
"CYCLE",
"DATA",
"DATE",
"DAY",
"DEALLOCATE",
"DEC",
"DECIMAL",
"DECLARE",
"DEFAULT",
"DEFERRABLE",
"DEFERRED",
"DELETE",
"DEPTH",
"DEREF",
"DESC",
"DESCRIBE",
"DESCRIPTOR",
"DETERMINISTIC",
"DIAGNOSTICS",
"DISCONNECT",
"DISTINCT",
"DO",
"DOMAIN",
"DOUBLE",
"DROP",
"DYNAMIC",
"EACH",
"ELEMENT",
"ELSE",
"ELSEIF",
"END",
"EQUALS",
"ESCAPE",
"EXCEPT",
"EXCEPTION",
"EXEC",
"EXECUTE",
"EXISTS",
"EXIT",
"external",
"EXTRACT",
"FALSE",
"FETCH",
"FILTER",
"FIRST",
"FLOAT",
"FOR",
"FOREIGN",
"FOUND",
"FREE",
"FROM",
"FULL",
"FUNCTION",
"GENERAL",
"GET",
"GLOBAL",
"GO",
"GOTO",
"GRANT",
"GROUP",
"GROUPING",
"HANDLER",
"HAVING",
"HOLD",
"HOUR",
"IDENTITY",
"IF",
"IMMEDIATE",
"IN",
"INDICATOR",
"INITIALLY",
"INNER",
"INOUT",
"INPUT",
"INSENSITIVE",
"INSERT",
"INT",
"INTEGER",
"INTERSECT",
"INTERVAL",
"INTO",
"IS",
"ISOLATION",
"ITERATE",
"JOIN",
"KEY",
"LANGUAGE",
"LARGE",
"LAST",
"LATERAL",
"LEADING",
"LEAVE",
"LEFT",
"LEVEL",
"LIKE",
"LOCAL",
"LOCALTIME",
"LOCALTIMESTAMP",
"LOCATOR",
"LOOP",
"LOWER",
"MAP",
"MATCH",
"MAX",
"MEMBER",
"MERGE",
"METHOD",
"MIN",
"MINUTE",
"MODIFIES",
"MODULE",
"MONTH",
"MULTISET",
"NAMES",
"NATIONAL",
"NATURAL",
"NCHAR",
"NCLOB",
"NEW",
"NEXT",
"NO",
"NONE",
"NOT",
"NULL",
"NULLIF",
"NUMERIC",
"OBJECT",
"OCTET_LENGTH",
"OF",
"OLD",
"ON",
"ONLY",
"OPEN",
"OPTION",
"OR",
"ORDER",
"ORDINALITY",
"OUT",
"OUTER",
"OUTPUT",
"OVER",
"OVERLAPS",
"PAD",
"PARAMETER",
"PARTIAL",
"PARTITION",
"PATH",
"POSITION",
"PRECISION",
"PREPARE",
"PRESERVE",
"PRIMARY",
"PRIOR",
"PRIVILEGES",
"PROCEDURE",
"PUBLIC",
"RANGE",
"READ",
"READS",
"REAL",
"RECURSIVE",
"REF",
"REFERENCES",
"REFERENCING",
"RELATIVE",
"RELEASE",
"REPEAT",
"RESIGNAL",
"RESTRICT",
"RESULT",
"RETURN",
"RETURNS",
"REVOKE",
"RIGHT",
"ROLE",
"ROLLBACK",
"ROLLUP",
"ROUTINE",
"ROW",
"ROWS",
"SAVEPOINT",
"SCHEMA",
"SCOPE",
"SCROLL",
"SEARCH",
"SECOND",
"SECTION",
"SELECT",
"SENSITIVE",
"SESSION",
"SESSION_USER",
"SET",
"SETS",
"SIGNAL",
"SIMILAR",
"SIZE",
"SMALLINT",
"SOME",
"SPACE",
"SPECIFIC",
"SPECIFICTYPE",
"SQL",
"SQLCODE",
"SQLERROR",
"SQLEXCEPTION",
"SQLSTATE",
"SQLWARNING",
"START",
"STATE",
"STATIC",
"SUBMULTISET",
"SUBSTRING",
"SUM",
"SYMMETRIC",
"SYSTEM",
"SYSTEM_USER",
"TABLE",
"TABLESAMPLE",
"TEMPORARY",
"THEN",
"TIME",
"TIMESTAMP",
"TIMEZONE_HOUR",
"TIMEZONE_MINUTE",
"TO",
"TRAILING",
"TRANSACTION",
"TRANSLATE",
"TRANSLATION",
"TREAT",
"TRIGGER",
"TRIM",
"TRUE",
"UNDER",
"UNDO",
"UNION",
"UNIQUE",
"UNKNOWN",
"UNNEST",
"UNTIL",
"UPDATE",
"UPPER",
"USAGE",
"USER",
"USING",
"VALUE",
"VALUES",
"VARCHAR",
"VARYING",
"VIEW",
"WHEN",
"WHENEVER",
"WHERE",
"WHILE",
"WINDOW",
"WITH",
"WITHIN",
"WITHOUT",
"WORK",
"WRITE",
"YEAR",
"ZONE",
NULL
};
char **pw = reserved;
while (*pw != NULL)
{
if (strcasecmp (name, *pw) == 0)
return 1;
pw++;
}
return 0;
}
GAIAAUX_DECLARE char *
gaiaDequotedSql (const char *value)
{
const char *pi = value;
const char *start;
const char *end;
char *clean;
char *po;
int len;
char target;
int mark = 0;
if (value == NULL)
return NULL;
len = strlen (value);
clean = malloc (len + 1);
if (*(value + 0) == '"' && *(value + len - 1) == '"')
target = '"';
else if (*(value + 0) == '\'' && *(value + len - 1) == '\'')
target = '\'';
else
{
strcpy (clean, value);
return clean;
}
start = value;
end = value + len - 1;
po = clean;
while (*pi != '\0')
{
if (mark)
{
if (*pi == target)
{
*po++ = *pi++;
mark = 0;
continue;
}
else
{
free (clean);
return NULL;
}
}
if (*pi == target)
{
if (pi == start || pi == end)
{
pi++;
continue;
}
mark = 1;
pi++;
continue;
}
*po++ = *pi++;
}
*po = '\0';
return clean;
}
GAIAAUX_DECLARE char *
gaiaQuotedSql (const char *value, int quote)
{
const char *p_in;
const char *p_end;
char qt;
char *out;
char *p_out;
int len = 0;
int i;
if (!value)
return NULL;
if (quote == GAIA_SQL_SINGLE_QUOTE)
qt = '\'';
else if (quote == GAIA_SQL_DOUBLE_QUOTE)
qt = '"';
else
return NULL;
p_end = value;
for (i = (strlen (value) - 1); i >= 0; i--)
{
p_end = value + i;
if (value[i] != ' ')
break;
}
p_in = value;
while (p_in <= p_end)
{
len++;
if (*p_in == qt)
len++;
p_in++;
}
if (len == 1 && *value == ' ')
{
len = 0;
}
out = malloc (len + 1);
if (!out)
return NULL;
if (len == 0)
{
*out = '\0';
return out;
}
p_out = out;
p_in = value;
while (p_in <= p_end)
{
if (*p_in == qt)
*p_out++ = qt;
*p_out++ = *p_in++;
}
*p_out = '\0';
return out;
}
GAIAAUX_DECLARE char *
gaiaSingleQuotedSql (const char *value)
{
return gaiaQuotedSql (value, GAIA_SQL_SINGLE_QUOTE);
}
GAIAAUX_DECLARE char *
gaiaDoubleQuotedSql (const char *value)
{
return gaiaQuotedSql (value, GAIA_SQL_DOUBLE_QUOTE);
}
GAIAAUX_DECLARE void
gaiaCleanSqlString (char *value)
{
char new_value[1024];
char *p;
int len;
int i;
len = strlen (value);
for (i = (len - 1); i >= 0; i--)
{
if (value[i] == ' ')
value[i] = '\0';
else
break;
}
p = new_value;
for (i = 0; i < len; i++)
{
if (value[i] == '\'')
*(p++) = '\'';
*(p++) = value[i];
}
*p = '\0';
strcpy (value, new_value);
}
GAIAAUX_DECLARE void
gaiaInsertIntoSqlLog (sqlite3 * sqlite, const char *user_agent,
const char *utf8Sql, sqlite3_int64 * sqllog_pk)
{
char *sql_statement;
int ret;
*sqllog_pk = -1;
if (checkSpatialMetaData (sqlite) != 3)
{
return;
}
sql_statement = sqlite3_mprintf ("INSERT INTO sql_statements_log "
"(id, time_start, user_agent, sql_statement) VALUES ("
"NULL, strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), %Q, %Q)",
user_agent, utf8Sql);
ret = sqlite3_exec (sqlite, sql_statement, NULL, 0, NULL);
sqlite3_free (sql_statement);
if (ret != SQLITE_OK)
return;
*sqllog_pk = sqlite3_last_insert_rowid (sqlite);
}
GAIAAUX_DECLARE void
gaiaUpdateSqlLog (sqlite3 * sqlite, sqlite3_int64 sqllog_pk, int success,
const char *errMsg)
{
char *sql_statement;
char dummy[64];
if (checkSpatialMetaData (sqlite) != 3)
{
return;
}
sprintf (dummy, FRMT64, sqllog_pk);
if (success)
{
sql_statement = sqlite3_mprintf ("UPDATE sql_statements_log SET "
"time_end = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
"success = 1, error_cause = 'success' WHERE id = %s",
dummy);
}
else
{
sql_statement = sqlite3_mprintf ("UPDATE sql_statements_log SET "
"time_end = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
"success = 0, error_cause = %Q WHERE id = %s",
(errMsg == NULL)
? "UNKNOWN" : errMsg, dummy);
}
sqlite3_exec (sqlite, sql_statement, NULL, 0, NULL);
sqlite3_free (sql_statement);
}
static void
consume_blank (const char *p_start, const char **p_end)
{
const char *p = p_start;
while (1)
{
if (*p == ' ' || *p == '\t')
{
p++;
continue;
}
else
{
*p_end = p;
return;
}
}
}
static int
check_deg_delimiter (const char *p_start, const char **p_end)
{
unsigned char ctrl1;
unsigned char ctrl2;
if (*p_start == 'd')
{
*p_end = p_start + 1;
return 1;
}
ctrl1 = *(p_start + 0);
ctrl2 = *(p_start + 1);
if (ctrl1 == 0xc2 && ctrl2 == 0xb0)
{
*p_end = p_start + 2;
return 1;
}
return 0;
}
static int
check_min_delimiter (const char *p_start, const char **p_end)
{
unsigned char ctrl1;
unsigned char ctrl2;
unsigned char ctrl3;
if (*p_start == '\'')
{
*p_end = p_start + 1;
return 1;
}
ctrl1 = *(p_start + 0);
ctrl2 = *(p_start + 1);
ctrl3 = *(p_start + 2);
if (ctrl1 == 0xe2 && ctrl2 == 0x80 && ctrl3 == 0xb2)
{
*p_end = p_start + 3;
return 1;
}
return 0;
}
static int
check_sec_delimiter (const char *p_start, const char **p_end)
{
unsigned char ctrl1;
unsigned char ctrl2;
unsigned char ctrl3;
if (*p_start == '"')
{
*p_end = p_start + 1;
return 1;
}
ctrl1 = *(p_start + 0);
ctrl2 = *(p_start + 1);
ctrl3 = *(p_start + 2);
if (ctrl1 == 0xe2 && ctrl2 == 0x80 && ctrl3 == 0xb3)
{
*p_end = p_start + 3;
return 1;
}
return 0;
}
static void
consume_int (const char *p_start, const char **p_end, int *value)
{
char *buf;
int len = 0;
const char *p = p_start;
while (1)
{
if (*p >= '0' && *p <= '9')
{
len++;
p++;
continue;
}
else
{
*p_end = p;
break;
}
}
if (len == 0)
{
*value = 181;
return;
}
buf = malloc (len + 1);
memcpy (buf, p_start, len);
*(buf + len) = '\0';
*value = atoi (buf);
free (buf);
}
static void
consume_float (const char *p_start, const char **p_end, double *value)
{
char *buf;
int pt = 0;
int len = 0;
const char *p = p_start;
while (1)
{
if (*p >= '0' && *p <= '9')
{
len++;
p++;
continue;
}
else if (*p == '.' || *p == ',')
{
len++;
pt++;
p++;
continue;
}
else
{
*p_end = p;
break;
}
}
if (len == 0 || pt > 1)
{
*value = 61.0;
return;
}
buf = malloc (len + 1);
memcpy (buf, p_start, len);
*(buf + len) = '\0';
*value = atof (buf);
free (buf);
}
GAIAAUX_DECLARE int
gaiaParseDMS (const char *dms, double *longitude, double *latitude)
{
double lg;
double lt;
int lat_d;
int lat_m;
double lat_s;
char lat_prefix = '\0';
int long_d;
int long_m;
double long_s;
char long_prefix = '\0';
const char *p = dms;
const char *p_end;
if (dms == NULL)
return 0;
consume_blank (p, &p_end);
p = p_end;
if (*p == 'S' || *p == 'N')
{
lat_prefix = *p;
p++;
consume_blank (p, &p_end);
p = p_end;
}
if (*p >= '0' && *p <= '9')
{
consume_int (p, &p_end, &lat_d);
if (lat_d < 0 && lat_d > 90)
return 0;
p = p_end;
}
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (check_deg_delimiter (p, &p_end))
p = p_end;
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (*p >= '0' && *p <= '9')
{
consume_int (p, &p_end, &lat_m);
if (lat_m < 0 && lat_m >= 60)
return 0;
p = p_end;
}
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (check_min_delimiter (p, &p_end))
p = p_end;
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (*p >= '0' && *p <= '9')
{
consume_float (p, &p_end, &lat_s);
if (lat_s < 0.0 && lat_s >= 60.0)
return 0;
p = p_end;
}
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (check_sec_delimiter (p, &p_end))
p = p_end;
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (lat_prefix == '\0')
{
if (*p == 'S' || *p == 'N')
{
lat_prefix = *p;
p++;
}
else
return 0;
}
lt = (double) lat_d + ((double) lat_m / 60.0) + (lat_s / 3600.0);
if (lat_prefix == 'S')
lt *= -1.0;
if (lt < -90.0 || lt > 90.0)
return 0;
consume_blank (p, &p_end);
p = p_end;
if (*p == 'E' || *p == 'W')
{
long_prefix = *p;
p++;
consume_blank (p, &p_end);
p = p_end;
}
if (*p >= '0' && *p <= '9')
{
consume_int (p, &p_end, &long_d);
if (long_d < 0 && long_d > 90)
return 0;
p = p_end;
}
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (check_deg_delimiter (p, &p_end))
p = p_end;
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (*p >= '0' && *p <= '9')
{
consume_int (p, &p_end, &long_m);
if (long_m < 0 && long_m >= 60)
return 0;
p = p_end;
}
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (check_min_delimiter (p, &p_end))
p = p_end;
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (*p >= '0' && *p <= '9')
{
consume_float (p, &p_end, &long_s);
if (long_s < 0.0 && long_s >= 60.0)
return 0;
p = p_end;
}
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (check_sec_delimiter (p, &p_end))
p = p_end;
else
return 0;
consume_blank (p, &p_end);
p = p_end;
if (long_prefix == '\0')
{
if (*p == 'E' || *p == 'W')
{
long_prefix = *p;
p++;
}
else
return 0;
}
lg = (double) long_d + ((double) long_m / 60.0) + (long_s / 3600.0);
if (long_prefix == 'W')
lg *= -1.0;
if (lg < -180.0 || lg > 180.0)
return 0;
*longitude = lg;
*latitude = lt;
return 1;
}
GAIAAUX_DECLARE char *
gaiaConvertToDMS (double longitude, double latitude)
{
char *dms0;
char *dms;
char long_prefix = 'E';
char lat_prefix = 'N';
int long_d;
int long_m;
int long_s;
int lat_d;
int lat_m;
int lat_s;
double val;
int len;
if (longitude < -180.0 || longitude > 180.0)
return NULL;
if (latitude < -90.0 || latitude > 90.0)
return NULL;
if (longitude < 0.0)
{
long_prefix = 'W';
longitude *= -1.0;
}
if (latitude < 0.0)
{
lat_prefix = 'S';
latitude *= -1.0;
}
long_d = (int) floor (longitude);
val = 60.0 * (longitude - (double) long_d);
long_m = (int) floor (val);
val = 60.0 * (val - (double) long_m);
long_s = (int) floor (val);
if ((val - (double) long_s) > 0.5)
long_s++;
lat_d = (int) floor (latitude);
val = 60.0 * (latitude - (double) lat_d);
lat_m = (int) floor (val);
val = 60.0 * (val - (double) lat_m);
lat_s = (int) floor (val);
if ((val - (double) lat_s) > 0.5)
lat_s++;
dms0 =
sqlite3_mprintf ("%02d°%02d′%02d″%c %03d°%02d′%02d″%c", lat_d,
lat_m, lat_s, lat_prefix, long_d, long_m, long_s,
long_prefix);
len = strlen (dms0);
dms = malloc (len + 1);
strcpy (dms, dms0);
sqlite3_free (dms0);
return dms;
}
static char
url_to_hex (char code)
{
static char hex[] = "0123456789abcdef";
return hex[code & 15];
}
GAIAAUX_DECLARE char *
gaiaEncodeURL (const char *url)
{
char *encoded = NULL;
const char *in = url;
char *out;
int len;
if (url == NULL)
return NULL;
len = strlen (url);
if (len == 0)
return NULL;
encoded = malloc ((len * 3) + 1);
out = encoded;
while (*in != '\0')
{
if (isalnum (*in) || *in == '-' || *in == '_' || *in == '.'
|| *in == '~')
*out++ = *in;
else if (*in == ' ')
*out++ = '+';
else
{
*out++ = '%';
*out++ = url_to_hex (*in >> 4);
*out++ = url_to_hex (*in & 15);
}
in++;
}
*out = '\0';
return encoded;
}
static char
url_from_hex (char ch)
{
return isdigit (ch) ? ch - '0' : tolower (ch) - 'a' + 10;
}
GAIAAUX_DECLARE char *
gaiaDecodeURL (const char *encoded)
{
char *url = NULL;
const char *in = encoded;
char *out;
int len;
if (encoded == NULL)
return NULL;
len = strlen (encoded);
if (len == 0)
return NULL;
url = malloc (len + 1);
out = url;
while (*in != '\0')
{
if (*in == '%')
{
if (*(in + 1) && *(in + 2))
{
*out++ =
url_from_hex (*(in + 1)) << 4 |
url_from_hex (*(in + 2));
in += 2;
}
}
else if (*in == '+')
*out++ = ' ';
else
*out++ = *in;
in++;
}
*out = '\0';
return url;
}
GAIAAUX_DECLARE char *
gaiaDirNameFromPath (const char *path)
{
const char *in = path;
const char *last = NULL;
int len = 0;
int dirlen;
char *name;
if (path == NULL)
return NULL;
while (*in != '\0')
{
len++;
if (*in == '/' || *in == '\\')
{
last = in;
dirlen = len;
}
in++;
}
if (last == NULL)
return NULL;
name = malloc (dirlen + 1);
memcpy (name, path, dirlen);
*(name + dirlen) = '\0';
return name;
}
GAIAAUX_DECLARE char *
gaiaFullFileNameFromPath (const char *path)
{
const char *in = path;
const char *last = path - 1;
int len;
char *name;
if (path == NULL)
return NULL;
while (*in != '\0')
{
if (*in == '/' || *in == '\\')
last = in;
in++;
}
len = strlen (last + 1);
if (len == 0)
return NULL;
name = malloc (len + 1);
strcpy (name, last + 1);
return name;
}
GAIAAUX_DECLARE char *
gaiaFileNameFromPath (const char *path)
{
const char *in = path;
const char *last = path - 1;
int len;
char *name;
int i;
if (path == NULL)
return NULL;
while (*in != '\0')
{
if (*in == '/' || *in == '\\')
last = in;
in++;
}
len = strlen (last + 1);
if (len == 0)
return NULL;
name = malloc (len + 1);
strcpy (name, last + 1);
for (i = len - 1; i > 0; i--)
{
if (*(name + i) == '.')
{
*(name + i) = '\0';
break;
}
}
return name;
}
GAIAAUX_DECLARE char *
gaiaFileExtFromPath (const char *path)
{
int len;
char *name;
int i;
int pos = -1;
if (path == NULL)
return NULL;
len = strlen (path);
for (i = len - 1; i > 0; i--)
{
if (*(path + i) == '/' || *(path + i) == '\\')
break;
if (*(path + i) == '.')
{
pos = i;
break;
}
}
if (pos <= 0)
return NULL;
len = strlen (path + pos + 1);
if (len == 0)
return NULL;
name = malloc (len + 1);
strcpy (name, path + pos + 1);
return name;
}