%% options
copyright owner = Dirk Krause
copyright year = 2015-xxxx
license = bsd
%% header
/** @file
String operations for path names
(wchar_t 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
dk4pathw_is_absolute(const wchar_t *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
dk4pathw_is_relative(const wchar_t *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
dk4pathw_append(
wchar_t *buffer, size_t sz, const wchar_t *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.
*/
wchar_t *
dk4pathw_get_suffix(const wchar_t *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
dk4pathw_correct_sep(wchar_t *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
dk4pathw_must_expand(const wchar_t *filename);
#ifdef __cplusplus
}
#endif
%% module
#include "dk4pathw.h"
#include "dk4mem.h"
#include "dk4strw.h"
#if DK4_HAVE_STRING_H
#ifndef STRING_H_INCLUDED
#include
#define STRING_H_INCLUDED 1
#endif
#endif
#if DK4_HAVE_WCHAR_H
#ifndef WCHAR_H_INCLUDED
#include
#define WCHAR_H_INCLUDED 1
#endif
#endif
/** Constant keywords used by the dk4pathw module.
*/
static const wchar_t * const dk4pathw_kw[] = {
#if DK4_HAVE_BACKSLASH_AS_SEP
/* 0 */ L"\\",
/* 1 */ L"/",
#else
/* 0 */ L"/",
/* 1 */ L"\\",
#endif
/* 2 */ L".",
/* 3 */ L"..",
/* 4 */ L":"
};
/** Get last character from a string.
@param str String to test.
@return Last character from string.
*/
static
wchar_t
dk4pathw_lastchar(const wchar_t *str)
{
wchar_t back = '\0';
if (str) { while (L'\0' != *str) { back = *(str++); } }
return back;
}
int
dk4pathw_is_absolute(const wchar_t *path)
{
int back = 0;
#if DK4_ON_WINDOWS
wchar_t c;
#endif
if (NULL != path) {
#if DK4_ON_WINDOWS
c = *path;
if ( *(dk4pathw_kw[0]) == c ) {
back = 1;
} else {
if (((L'a' <= c) && (L'z' >= c)) || ((L'A' <= c) && (L'Z' >= c))) {
if ( *(dk4pathw_kw[4]) == path[1] ) {
c = path[2];
if ( ( *(dk4pathw_kw[0]) == c ) || ( L'\0' == c ) ) {
back = 1;
}
}
}
}
#else
if ( *(dk4pathw_kw[0]) == *path ) {
back = 1;
}
#endif
}
return back;
}
int
dk4pathw_is_relative(const wchar_t *path)
{
int back = 0;
if (NULL != path) {
if (NULL != dk4strw_chr(path, *(dk4pathw_kw[0]))) {
if (0 == dk4pathw_is_absolute(path)) {
back = 1;
}
}
}
return back;
}
int
dk4pathw_append(
wchar_t *buffer, size_t sz, const wchar_t *filename, dk4_er_t *erp
)
{
wchar_t *pc; /* Current path part to append */
wchar_t *pn; /* Next part to append */
wchar_t *pd; /* Part to delete */
wchar_t *mycp = NULL; /* Private copy */
#if DK4_ON_WINDOWS
int ischr;
#endif
int back = 0; /* Function result */
int failed = 0; /* Definitely failed */
wchar_t lch; /* Last character from string */
if ((NULL != buffer) && (NULL != filename) && (0 < sz)) {
mycp = dk4strw_dup(filename, erp);
if (NULL != mycp) {
pc = mycp;
while ((NULL != pc) && (0 == failed)) {
pn = dk4strw_chr(pc, *(dk4pathw_kw[0]));
if (NULL != pn) { *(pn++) = L'\0'; }
if (0 != dk4strw_cmp(pc, dk4pathw_kw[2])) {
if (0 == dk4strw_cmp(pc, dk4pathw_kw[3])) { /* Remove from buffer */
pd = dk4strw_rchr(buffer, *(dk4pathw_kw[0]));
if (NULL != pd) {
*pd = L'\0';
if (0 < dk4strw_len(&(pd[1]))) {
#if DK4_ON_WINDOWS
if (2 == dk4strw_len(buffer)) {
ischr = 0;
if ((L'A' <= buffer[0]) && (L'Z' >= buffer[0])) {
ischr = 1;
}
if ((L'a' <= buffer[0]) && (L'z' >= buffer[0])) {
ischr = 1;
}
if (1 == ischr) {
if (L':' == buffer[1]) {
buffer[2] = *(dk4pathw_kw[0]);
buffer[3] = L'\0';
}
}
}
#else
if (0 == dk4strw_len(buffer)) {
*pd = *(dk4pathw_kw[0]);
pd++;
*pd = L'\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 = dk4pathw_lastchar(buffer);
if (lch != *(dk4pathw_kw[0])) {
if (0 != dk4strw_cat_s(buffer, sz, dk4pathw_kw[0], erp)) {
if (0 == dk4strw_cat_s(buffer, sz, pc, erp)) {
failed = 1;
}
} else {
failed = 1;
}
} else {
if (0 == dk4strw_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;
}
wchar_t *
dk4pathw_get_suffix(const wchar_t *filename, dk4_er_t *erp)
{
const wchar_t *back = NULL;
if (NULL != filename) {
while (L'\0' != *filename) {
if ((L'\\' == *filename) || (L'/' == *filename)) {
back = NULL;
} else {
if (L'.' == *filename) {
back = filename;
}
}
filename++;
}
} else {
dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
}
return ((wchar_t *)back);
}
void
dk4pathw_correct_sep(wchar_t *filename)
{
if (NULL != filename) {
while (L'\0' != *filename) {
#if DK4_HAVE_BACKSLASH_AS_SEP
if (L'/' == *filename) { *filename = L'\\'; }
#else
if (L'\\' == *filename) { *filename = L'/'; }
#endif
filename++;
}
}
}
int
dk4pathw_must_expand(const wchar_t *filename)
{
#if DK4_ON_WINDOWS
int back = 0;
if (NULL != filename) {
if (L'\\' == filename[0]) {
if (L'\\' == filename[1]) {
if (L'?' == filename[2]) {
if (L'\\' == filename[3]) {
filename = &(filename[4]);
}
}
}
}
while((L'\0' != *filename) && (0 == back)) {
if (L'*' == *filename) {
back = 1;
} else {
if (L'?' == *filename) {
back = 1;
} else {
filename++;
}
}
}
}
return back;
#else
return 0;
#endif
}