%% options
copyright owner = Dirk Krause
copyright year = 2015-xxxx
license = bsd
%% header
/** @file
String operations for path names
(8 bit characters).
*/
#ifndef DK4CONF_H_INCLUDED
#include "dk4conf.h"
#endif
#ifndef DK4TYPES_H_INCLUDED
#include "dk4types.h"
#endif
#ifndef DK4ERROR_H_INCLUDED
#include "dk4error.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** Check whether a file name is an absolute path.
CRT on Windows: Not used.
@param path Path name to check.
@return 1 for absolute path, 0 for other path.
*/
int
dk4path8_is_absolute(const char *path);
/** Check whether a file name is a relative path.
CRT on Windows: Not used.
@param path Path name to check.
@return 1 for absolute path, 0 for other path.
*/
int
dk4path8_is_relative(const char *path);
/** Append path filename to path name already stored in buffer.
CRT on Windows: Optional, disabling CRT degrades performance.
@param buffer Buffer already containing a path.
@param sz Buffer size.
@param filename Relative file name to append to buffer.
@param erp Error report, may be NULL.
@return 1 on success, 0 on error.
Error codes:
- DK4_E_INVALID_ARGUMENTS
if buffer or filename is NULL or sz is 0,
- DK4_E_MATH_OVERFLOW
if filename is too long,
- DK4_E_MEMORY
if allocation of a filename copy fails,
- DK4_E_SYNTAX
if too many .. in filename,
- DK4_E_BUFFER_TOO_SMALL
if buffer size is too small.
*/
int
dk4path8_append(char *buffer, size_t sz, const char *filename, dk4_er_t *erp);
/** Find pointer to suffix.
CRT on Windows: Not used.
@param filename File name to find suffix for.
@param erp Error report, may be NULL.
@return Pointer to suffix dot if found, NULL otherwise.
Error codes:
- DK4_E_INVALID_ARGUMENTS
if filename is NULL,
- DK4_E_NOT_FOUND
if the file name does not contain a suffix.
*/
char *
dk4path8_get_suffix(const char *filename, dk4_er_t *erp);
/** Correct file name separators from slash to backslash on Windows,
vice versa on other systems.
CRT on Windows: Not used.
@param filename File name to correct.
*/
void
dk4path8_correct_sep(char *filename);
/** Check whether file name needs expansion on Windows.
CRT on Windows: Not used.
@param filename File name to check.
@return 1 if expansion is necessary, 0 otherwise.
*/
int
dk4path8_must_expand(const char *filename);
#ifdef __cplusplus
}
#endif
%% module
#include "dk4path8.h"
#include "dk4mem.h"
#include "dk4str8.h"
#if DK4_HAVE_STRING_H
#ifndef STRING_H_INCLUDED
#include
#define STRING_H_INCLUDED 1
#endif
#endif
/** Constant keywords used by the dk4path8 module.
*/
static const char * const dk4path8_kw[] = {
#if DK4_HAVE_BACKSLASH_AS_SEP
/* 0 */ "\\",
/* 1 */ "/",
#else
/* 0 */ "/",
/* 1 */ "\\",
#endif
/* 2 */ ".",
/* 3 */ "..",
/* 4 */ ":"
};
/** Get last character from a string.
CRT on Windows: Not used.
@param str String to test.
@return Last character from string.
*/
static
char
dk4path8_lastchar(const char *str)
{
char back = '\0';
if (str) { while ('\0' != *str) { back = *(str++); } }
return back;
}
int
dk4path8_is_absolute(const char *path)
{
int back = 0;
#if DK4_ON_WINDOWS
char c;
#endif
if (NULL != path) {
#if DK4_ON_WINDOWS
c = *path;
if ( *(dk4path8_kw[0]) == c ) {
back = 1;
} else {
if ((('a' <= c) && ('z' >= c)) || (('A' <= c) && ('Z' >= c))) {
if ( *(dk4path8_kw[4]) == path[1] ) {
c = path[2];
if ( ( *(dk4path8_kw[0]) == c ) || ( '\0' == c ) ) {
back = 1;
}
}
}
}
#else
if ( *(dk4path8_kw[0]) == *path ) {
back = 1;
}
#endif
}
return back;
}
int
dk4path8_is_relative(const char *path)
{
int back = 0;
if (NULL != path) {
if (NULL != dk4str8_chr(path, *(dk4path8_kw[0]))) {
if (0 == dk4path8_is_absolute(path)) {
back = 1;
}
}
}
return back;
}
int
dk4path8_append(char *buffer, size_t sz, const char *filename, dk4_er_t *erp)
{
char *pc; /* Current path part to append */
char *pn; /* Next part to append */
char *pd; /* Part to delete */
char *mycp = NULL; /* Private copy */
#if DK4_ON_WINDOWS
int ischr;
#endif
int back = 0; /* Function result */
int failed = 0; /* Definitely failed */
char lch; /* Last character from string */
if ((NULL != buffer) && (NULL != filename) && (0 < sz)) {
mycp = dk4str8_dup(filename, erp);
if (NULL != mycp) {
pc = mycp;
while ((NULL != pc) && (0 == failed)) {
pn = dk4str8_chr(pc, *(dk4path8_kw[0]));
if (NULL != pn) { *(pn++) = '\0'; }
if (0 != dk4str8_cmp(pc, dk4path8_kw[2])) {
if (0 == dk4str8_cmp(pc, dk4path8_kw[3])) { /* Remove from buffer */
pd = dk4str8_rchr(buffer, *(dk4path8_kw[0]));
if (NULL != pd) {
*pd = '\0';
if (0 < dk4str8_len(&(pd[1]))) {
#if DK4_ON_WINDOWS
if (2 == dk4str8_len(buffer)) {
ischr = 0;
if (('A' <= buffer[0]) && ('Z' >= buffer[0])) {
ischr = 1;
}
if (('a' <= buffer[0]) && ('z' >= buffer[0])) {
ischr = 1;
}
if (1 == ischr) {
if (':' == buffer[1]) {
buffer[2] = *(dk4path8_kw[0]);
buffer[3] = '\0';
}
}
}
#else
if (0 == dk4str8_len(buffer)) {
*pd = *(dk4path8_kw[0]);
pd++;
*pd = '\0';
}
#endif
} else {
failed = 1;
dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
}
} else {
failed = 1;
dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
}
} else { /* Add to buffer */
lch = dk4path8_lastchar(buffer);
if (lch != *(dk4path8_kw[0])) {
if (0 != dk4str8_cat_s(buffer, sz, dk4path8_kw[0], erp)) {
if (0 == dk4str8_cat_s(buffer, sz, pc, erp)) {
failed = 1;
}
} else {
failed = 1;
}
} else {
if (0 == dk4str8_cat_s(buffer, sz, pc, erp)) {
failed = 1;
}
}
}
}
pc = pn;
}
if (0 == failed) {
back = 1;
}
dk4mem_release(mycp);
}
} else {
dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
}
return back;
}
char *
dk4path8_get_suffix(const char *filename, dk4_er_t *erp)
{
const char *back = NULL;
if (NULL != filename) {
while ('\0' != *filename) {
if (('\\' == *filename) || ('/' == *filename)) {
back = NULL;
} else {
if ('.' == *filename) {
back = filename;
}
}
filename++;
}
if (NULL == back) {
dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
}
} else {
dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
}
return ((char *)back);
}
void
dk4path8_correct_sep(char *filename)
{
if (NULL != filename) {
while ('\0' != *filename) {
#if DK4_HAVE_BACKSLASH_AS_SEP
if ('/' == *filename) { *filename = '\\'; }
#else
if ('\\' == *filename) { *filename = '/'; }
#endif
filename++;
}
}
}
int
dk4path8_must_expand(const char *filename)
{
#if DK4_ON_WINDOWS
int back = 0;
if (NULL != filename) {
while(('\0' != *filename) && (0 == back)) {
switch (*filename) {
case '*': case '?': {
back = 1;
} break;
default: {
filename++;
} break;
}
}
}
return back;
#else
return 0;
#endif
}