added path canonicalization functions
This commit is contained in:
		@ -32,6 +32,7 @@ include_HEADERS = \
 | 
			
		||||
	mio-http.h \
 | 
			
		||||
	mio-nwif.h \
 | 
			
		||||
	mio-pac1.h \
 | 
			
		||||
	mio-path.h \
 | 
			
		||||
	mio-pro.h \
 | 
			
		||||
	mio-sck.h \
 | 
			
		||||
	mio-skad.h \
 | 
			
		||||
@ -50,11 +51,13 @@ libmio_la_SOURCES = \
 | 
			
		||||
	fmt.c \
 | 
			
		||||
	fmt-imp.h \
 | 
			
		||||
	htb.c \
 | 
			
		||||
	htrd.c \
 | 
			
		||||
	htre.c \
 | 
			
		||||
	http.c \
 | 
			
		||||
	mio-prv.h \
 | 
			
		||||
	mio.c \
 | 
			
		||||
	nwif.c \
 | 
			
		||||
	path.c \
 | 
			
		||||
	pro.c \
 | 
			
		||||
	sck.c \
 | 
			
		||||
	skad.c \
 | 
			
		||||
 | 
			
		||||
@ -140,12 +140,13 @@ libmio_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
 | 
			
		||||
	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 | 
			
		||||
am_libmio_la_OBJECTS = libmio_la-chr.lo libmio_la-dns.lo \
 | 
			
		||||
	libmio_la-dns-cli.lo libmio_la-ecs.lo libmio_la-err.lo \
 | 
			
		||||
	libmio_la-fmt.lo libmio_la-htb.lo libmio_la-htre.lo \
 | 
			
		||||
	libmio_la-http.lo libmio_la-mio.lo libmio_la-nwif.lo \
 | 
			
		||||
	libmio_la-pro.lo libmio_la-sck.lo libmio_la-skad.lo \
 | 
			
		||||
	libmio_la-sys.lo libmio_la-sys-ass.lo libmio_la-sys-err.lo \
 | 
			
		||||
	libmio_la-sys-log.lo libmio_la-sys-mux.lo libmio_la-sys-tim.lo \
 | 
			
		||||
	libmio_la-tmr.lo libmio_la-utf8.lo libmio_la-utl.lo
 | 
			
		||||
	libmio_la-fmt.lo libmio_la-htb.lo libmio_la-htrd.lo \
 | 
			
		||||
	libmio_la-htre.lo libmio_la-http.lo libmio_la-mio.lo \
 | 
			
		||||
	libmio_la-nwif.lo libmio_la-path.lo libmio_la-pro.lo \
 | 
			
		||||
	libmio_la-sck.lo libmio_la-skad.lo libmio_la-sys.lo \
 | 
			
		||||
	libmio_la-sys-ass.lo libmio_la-sys-err.lo libmio_la-sys-log.lo \
 | 
			
		||||
	libmio_la-sys-mux.lo libmio_la-sys-tim.lo libmio_la-tmr.lo \
 | 
			
		||||
	libmio_la-utf8.lo libmio_la-utl.lo
 | 
			
		||||
libmio_la_OBJECTS = $(am_libmio_la_OBJECTS)
 | 
			
		||||
AM_V_lt = $(am__v_lt_@AM_V@)
 | 
			
		||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 | 
			
		||||
@ -173,9 +174,10 @@ am__depfiles_remade = ./$(DEPDIR)/libmio_la-chr.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-dns-cli.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-dns.Plo ./$(DEPDIR)/libmio_la-ecs.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-err.Plo ./$(DEPDIR)/libmio_la-fmt.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-htb.Plo ./$(DEPDIR)/libmio_la-htre.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-http.Plo ./$(DEPDIR)/libmio_la-mio.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-nwif.Plo ./$(DEPDIR)/libmio_la-pro.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-htb.Plo ./$(DEPDIR)/libmio_la-htrd.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-htre.Plo ./$(DEPDIR)/libmio_la-http.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-mio.Plo ./$(DEPDIR)/libmio_la-nwif.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-path.Plo ./$(DEPDIR)/libmio_la-pro.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sck.Plo ./$(DEPDIR)/libmio_la-skad.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sys-ass.Plo \
 | 
			
		||||
	./$(DEPDIR)/libmio_la-sys-err.Plo \
 | 
			
		||||
@ -412,6 +414,7 @@ include_HEADERS = \
 | 
			
		||||
	mio-http.h \
 | 
			
		||||
	mio-nwif.h \
 | 
			
		||||
	mio-pac1.h \
 | 
			
		||||
	mio-path.h \
 | 
			
		||||
	mio-pro.h \
 | 
			
		||||
	mio-sck.h \
 | 
			
		||||
	mio-skad.h \
 | 
			
		||||
@ -430,11 +433,13 @@ libmio_la_SOURCES = \
 | 
			
		||||
	fmt.c \
 | 
			
		||||
	fmt-imp.h \
 | 
			
		||||
	htb.c \
 | 
			
		||||
	htrd.c \
 | 
			
		||||
	htre.c \
 | 
			
		||||
	http.c \
 | 
			
		||||
	mio-prv.h \
 | 
			
		||||
	mio.c \
 | 
			
		||||
	nwif.c \
 | 
			
		||||
	path.c \
 | 
			
		||||
	pro.c \
 | 
			
		||||
	sck.c \
 | 
			
		||||
	skad.c \
 | 
			
		||||
@ -553,10 +558,12 @@ distclean-compile:
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-err.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-fmt.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-htb.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-htrd.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-htre.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-http.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-mio.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-nwif.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-path.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-pro.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-sck.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmio_la-skad.Plo@am__quote@ # am--include-marker
 | 
			
		||||
@ -649,6 +656,13 @@ libmio_la-htb.lo: htb.c
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 | 
			
		||||
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-htb.lo `test -f 'htb.c' || echo '$(srcdir)/'`htb.c
 | 
			
		||||
 | 
			
		||||
libmio_la-htrd.lo: htrd.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-htrd.lo -MD -MP -MF $(DEPDIR)/libmio_la-htrd.Tpo -c -o libmio_la-htrd.lo `test -f 'htrd.c' || echo '$(srcdir)/'`htrd.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-htrd.Tpo $(DEPDIR)/libmio_la-htrd.Plo
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='htrd.c' object='libmio_la-htrd.lo' libtool=yes @AMDEPBACKSLASH@
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 | 
			
		||||
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-htrd.lo `test -f 'htrd.c' || echo '$(srcdir)/'`htrd.c
 | 
			
		||||
 | 
			
		||||
libmio_la-htre.lo: htre.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-htre.lo -MD -MP -MF $(DEPDIR)/libmio_la-htre.Tpo -c -o libmio_la-htre.lo `test -f 'htre.c' || echo '$(srcdir)/'`htre.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-htre.Tpo $(DEPDIR)/libmio_la-htre.Plo
 | 
			
		||||
@ -677,6 +691,13 @@ libmio_la-nwif.lo: nwif.c
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 | 
			
		||||
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-nwif.lo `test -f 'nwif.c' || echo '$(srcdir)/'`nwif.c
 | 
			
		||||
 | 
			
		||||
libmio_la-path.lo: path.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-path.lo -MD -MP -MF $(DEPDIR)/libmio_la-path.Tpo -c -o libmio_la-path.lo `test -f 'path.c' || echo '$(srcdir)/'`path.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-path.Tpo $(DEPDIR)/libmio_la-path.Plo
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='path.c' object='libmio_la-path.lo' libtool=yes @AMDEPBACKSLASH@
 | 
			
		||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 | 
			
		||||
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmio_la-path.lo `test -f 'path.c' || echo '$(srcdir)/'`path.c
 | 
			
		||||
 | 
			
		||||
libmio_la-pro.lo: pro.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmio_la-pro.lo -MD -MP -MF $(DEPDIR)/libmio_la-pro.Tpo -c -o libmio_la-pro.lo `test -f 'pro.c' || echo '$(srcdir)/'`pro.c
 | 
			
		||||
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libmio_la-pro.Tpo $(DEPDIR)/libmio_la-pro.Plo
 | 
			
		||||
@ -923,10 +944,12 @@ distclean: distclean-am
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-err.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-fmt.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-htb.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-htrd.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-htre.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-http.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-mio.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-nwif.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-path.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-pro.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-sck.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-skad.Plo
 | 
			
		||||
@ -992,10 +1015,12 @@ maintainer-clean: maintainer-clean-am
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-err.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-fmt.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-htb.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-htrd.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-htre.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-http.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-mio.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-nwif.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-path.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-pro.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-sck.Plo
 | 
			
		||||
	-rm -f ./$(DEPDIR)/libmio_la-skad.Plo
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@
 | 
			
		||||
 | 
			
		||||
#include "mio-htrd.h"
 | 
			
		||||
#include "mio-chr.h"
 | 
			
		||||
#include "mio-path.h"
 | 
			
		||||
#include "mio-prv.h"
 | 
			
		||||
 | 
			
		||||
static const mio_bch_t NUL = '\0';
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										96
									
								
								mio/lib/mio-path.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								mio/lib/mio-path.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id$
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
    are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
       documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
			
		||||
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _MIO_PATH_H_
 | 
			
		||||
#define _MIO_PATH_H_
 | 
			
		||||
 | 
			
		||||
#include <mio.h>
 | 
			
		||||
#include <mio-utl.h>
 | 
			
		||||
 | 
			
		||||
enum mio_canon_path_flag_t
 | 
			
		||||
{
 | 
			
		||||
	/** if the final output is . logically, return an empty path */
 | 
			
		||||
	MIO_CANON_PATH_EMPTY_SINGLE_DOT    = (1 << 0),
 | 
			
		||||
 | 
			
		||||
	/** keep the .. segment in the path name */
 | 
			
		||||
	MIO_CANON_PATH_KEEP_DOUBLE_DOTS    = (1 << 1),
 | 
			
		||||
 | 
			
		||||
	/** drop a trailing separator even if the source contains one */
 | 
			
		||||
	MIO_CANON_PATH_DROP_TRAILING_SEP   = (1 << 2)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum mio_canon_path_flag_t mio_canon_path_flag_t;
 | 
			
		||||
 | 
			
		||||
#define MIO_CANON_OOCSTR_PATH_EMPTY_SINGLE_DOT MIO_CANON_PATH_EMPTY_SINGLE_DOT
 | 
			
		||||
#define MIO_CANON_OOCSTR_PATH_KEEP_DOUBLE_DOTS MIO_CANON_PATH_KEEP_DOUBLE_DOTS
 | 
			
		||||
#define MIO_CANON_OOCSTR_PATH_DROP_TRAILING_SEP MIO_CANON_PATH_DROP_TRAILING_SEP
 | 
			
		||||
 | 
			
		||||
#define MIO_CANON_UCSTR_PATH_EMPTY_SINGLE_DOT MIO_CANON_PATH_EMPTY_SINGLE_DOT
 | 
			
		||||
#define MIO_CANON_UCSTR_PATH_KEEP_DOUBLE_DOTS MIO_CANON_PATH_KEEP_DOUBLE_DOTS
 | 
			
		||||
#define MIO_CANON_UCSTR_PATH_DROP_TRAILING_SEP MIO_CANON_PATH_DROP_TRAILING_SEP
 | 
			
		||||
 | 
			
		||||
#define MIO_CANON_BCSTR_PATH_EMPTY_SINGLE_DOT MIO_CANON_PATH_EMPTY_SINGLE_DOT
 | 
			
		||||
#define MIO_CANON_BCSTR_PATH_KEEP_DOUBLE_DOTS MIO_CANON_PATH_KEEP_DOUBLE_DOTS
 | 
			
		||||
#define MIO_CANON_BCSTR_PATH_DROP_TRAILING_SEP MIO_CANON_PATH_DROP_TRAILING_SEP
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
 | 
			
		||||
#	define MIO_IS_PATH_SEP(c) ((c) == '/' || (c) == '\\')
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
#	define MIO_IS_PATH_SEP(c) ((c) == '/')
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MIO_IS_PATH_DRIVE(s) \
 | 
			
		||||
	(((s[0] >= 'A' && s[0] <= 'Z') || \
 | 
			
		||||
	  (s[0] >= 'a' && s[0] <= 'z')) && \
 | 
			
		||||
	 s[1] == ':')
 | 
			
		||||
 | 
			
		||||
#define MIO_IS_PATH_SEP_OR_NIL(c) (MIO_IS_PATH_SEP(c) || (c) == '\0')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT mio_oow_t mio_canon_ucstr_path (
 | 
			
		||||
	const mio_uch_t* path,
 | 
			
		||||
	mio_uch_t*       canon,
 | 
			
		||||
	int              flags
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MIO_EXPORT mio_oow_t mio_canon_bcstr_path (
 | 
			
		||||
	const mio_bch_t* path,
 | 
			
		||||
	mio_bch_t*       canon,
 | 
			
		||||
	int              flags
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#if defined(__cplusplus)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										641
									
								
								mio/lib/path.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										641
									
								
								mio/lib/path.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,641 @@
 | 
			
		||||
/*
 | 
			
		||||
 * $Id
 | 
			
		||||
 *
 | 
			
		||||
    Copyright (c) 2016-2020 Chung, Hyung-Hwan. All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions
 | 
			
		||||
    are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
       documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | 
			
		||||
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "mio-path.h"
 | 
			
		||||
#include "mio-prv.h"
 | 
			
		||||
 | 
			
		||||
/* TODO: support the \\?\ prefix and the \\.\ prefix on windows 
 | 
			
		||||
 *       support \\?\UNC\server\path which is equivalent to \\server\path. 
 | 
			
		||||
 * */
 | 
			
		||||
/* ------------------------------------------------------------------ */
 | 
			
		||||
/*  WCS IMPLEMENTATION                                                */
 | 
			
		||||
/* ------------------------------------------------------------------ */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
int mio_is_ucstr_path_absolute (const mio_uch_t* path)
 | 
			
		||||
{
 | 
			
		||||
	if (MIO_IS_PATH_SEP(path[0])) return 1;
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	/* a drive like c:tmp is absolute in positioning the drive.
 | 
			
		||||
	 * but the path within the drive is kind of relative */
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path)) return 1;
 | 
			
		||||
#endif
 | 
			
		||||
     return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_is_ucstr_path_drive (const mio_uch_t* path)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path)) return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_is_ucstr_path_drive_absolute (const mio_uch_t* path)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path) && MIO_IS_PATH_SEP(path[2])) return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_is_ucstr_path_drive_current (const mio_uch_t* path)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path) && path[2] == '\0') return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
mio_oow_t mio_canon_ucstr_path (const mio_uch_t* path, mio_uch_t* canon, int flags)
 | 
			
		||||
{
 | 
			
		||||
	const mio_uch_t* ptr;
 | 
			
		||||
	mio_uch_t* dst;
 | 
			
		||||
	mio_uch_t* non_root_start;
 | 
			
		||||
	int has_root = 0;
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	int is_drive = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	mio_oow_t canon_len;
 | 
			
		||||
 | 
			
		||||
	if (path[0] == '\0') 
 | 
			
		||||
	{
 | 
			
		||||
		/* if the source is empty, no translation is needed */
 | 
			
		||||
		canon[0] = '\0';
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ptr = path;
 | 
			
		||||
	dst = canon;
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(ptr))
 | 
			
		||||
	{
 | 
			
		||||
		/* handle drive letter */
 | 
			
		||||
		*dst++ = *ptr++; /* drive letter */
 | 
			
		||||
		*dst++ = *ptr++; /* colon */
 | 
			
		||||
 | 
			
		||||
		is_drive = 1;
 | 
			
		||||
		if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
		{
 | 
			
		||||
			*dst++ = *ptr++; /* root directory */
 | 
			
		||||
			has_root = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
	{
 | 
			
		||||
		*dst++ = *ptr++; /* root directory */
 | 
			
		||||
		has_root = 1;
 | 
			
		||||
 | 
			
		||||
	#if defined(_WIN32)
 | 
			
		||||
		/* handle UNC path for Windows */
 | 
			
		||||
		if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
		{
 | 
			
		||||
			*dst++ = *ptr++;
 | 
			
		||||
 | 
			
		||||
			if (MIO_IS_PATH_SEP_OR_NIL(*ptr))
 | 
			
		||||
			{
 | 
			
		||||
				/* if there is another separator after \\,
 | 
			
		||||
				 * it's not an UNC path. */
 | 
			
		||||
				dst--;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* if it starts with \\, process host name */
 | 
			
		||||
				do { *dst++ = *ptr++; } while (!MIO_IS_PATH_SEP_OR_NIL(*ptr));
 | 
			
		||||
				if (MIO_IS_PATH_SEP(*ptr)) *dst++ = *ptr++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	#endif
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
	{
 | 
			
		||||
		*dst++ = *ptr++; /* root directory */
 | 
			
		||||
		has_root = 1;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* non_root_start points to the beginning of the canonicalized 
 | 
			
		||||
	 * path excluding the root directory part. */
 | 
			
		||||
	non_root_start = dst;
 | 
			
		||||
 | 
			
		||||
	do
 | 
			
		||||
	{
 | 
			
		||||
		const mio_uch_t* seg;
 | 
			
		||||
		mio_oow_t seglen;
 | 
			
		||||
 | 
			
		||||
		/* skip duplicate separators */
 | 
			
		||||
		while (MIO_IS_PATH_SEP(*ptr)) ptr++;
 | 
			
		||||
 | 
			
		||||
		/* end of path reached */
 | 
			
		||||
		if (*ptr == '\0') break;
 | 
			
		||||
 | 
			
		||||
		/* find the next segment */
 | 
			
		||||
		seg = ptr;
 | 
			
		||||
		while (!MIO_IS_PATH_SEP_OR_NIL(*ptr)) ptr++;
 | 
			
		||||
		seglen = ptr - seg;
 | 
			
		||||
 | 
			
		||||
		/* handle the segment */
 | 
			
		||||
		if (seglen == 1 && seg[0] == '.')
 | 
			
		||||
		{
 | 
			
		||||
			/* eat up . */
 | 
			
		||||
		}
 | 
			
		||||
		else if (!(flags & MIO_CANON_UCSTR_PATH_KEEP_DOUBLE_DOTS) &&
 | 
			
		||||
		         seglen == 2 && seg[0] == '.' && seg[1] == '.')
 | 
			
		||||
		{
 | 
			
		||||
			/* eat up the previous segment */
 | 
			
		||||
			mio_uch_t* tmp;
 | 
			
		||||
 | 
			
		||||
			tmp = dst;
 | 
			
		||||
			if (tmp > non_root_start) 
 | 
			
		||||
			{
 | 
			
		||||
				/* there is a previous segment. */
 | 
			
		||||
 | 
			
		||||
				tmp--; /* skip the separator just before .. */
 | 
			
		||||
 | 
			
		||||
				/* find the beginning of the previous segment */
 | 
			
		||||
				while (tmp > non_root_start)
 | 
			
		||||
				{
 | 
			
		||||
					tmp--;
 | 
			
		||||
					if (MIO_IS_PATH_SEP(*tmp)) 
 | 
			
		||||
					{
 | 
			
		||||
						tmp++; /* position it next to the separator */
 | 
			
		||||
						break; 
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (has_root)
 | 
			
		||||
			{
 | 
			
		||||
				/*
 | 
			
		||||
				 * Eat up the previous segment if it exists.
 | 
			
		||||
				 *
 | 
			
		||||
				 * If it doesn't exist, tmp == dst so dst = tmp
 | 
			
		||||
				 * keeps dst unchanged. If it exists, 
 | 
			
		||||
				 * tmp != dst. so dst = tmp changes dst.
 | 
			
		||||
				 *
 | 
			
		||||
				 * path  /abc/def/..
 | 
			
		||||
				 *                ^ ^
 | 
			
		||||
				 *              seg ptr
 | 
			
		||||
				 *
 | 
			
		||||
				 * canon /abc/def/
 | 
			
		||||
				 *            ^   ^   
 | 
			
		||||
				 *           tmp dst
 | 
			
		||||
				 */
 | 
			
		||||
				dst = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				mio_oow_t prevlen;
 | 
			
		||||
 | 
			
		||||
				prevlen = dst - tmp;
 | 
			
		||||
 | 
			
		||||
				if (/*tmp == non_root_start &&*/ prevlen == 0)
 | 
			
		||||
				{
 | 
			
		||||
					/* there is no previous segment */
 | 
			
		||||
					goto normal;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (prevlen == 3 && tmp[0] == '.' && tmp[1] == '.') 
 | 
			
		||||
				{
 | 
			
		||||
					/* nothing to eat away because the previous segment is ../
 | 
			
		||||
					 *
 | 
			
		||||
					 * path  ../../
 | 
			
		||||
					 *          ^ ^
 | 
			
		||||
					 *        seg ptr
 | 
			
		||||
					 *
 | 
			
		||||
					 * canon ../
 | 
			
		||||
					 *       ^  ^
 | 
			
		||||
					 *      tmp dst
 | 
			
		||||
					 */
 | 
			
		||||
					goto normal;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				dst = tmp;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
		normal:
 | 
			
		||||
			while (seg < ptr) *dst++ = *seg++;
 | 
			
		||||
			if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
			{
 | 
			
		||||
				/* this segment ended with a separator */
 | 
			
		||||
				*dst++ = *seg++; /* copy the separator */
 | 
			
		||||
				ptr++; /* move forward the pointer */
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	while (1);
 | 
			
		||||
 | 
			
		||||
	if (dst > non_root_start && MIO_IS_PATH_SEP(dst[-1]) && 
 | 
			
		||||
	    ((flags & MIO_CANON_BCSTR_PATH_DROP_TRAILING_SEP) || !MIO_IS_PATH_SEP(ptr[-1]))) 
 | 
			
		||||
	{
 | 
			
		||||
		/* if the canoncal path composed so far ends with a separator
 | 
			
		||||
		 * and the original path didn't end with the separator, delete
 | 
			
		||||
		 * the ending separator. 
 | 
			
		||||
		 * also delete it if MIO_CANON_BCSTR_PATH_DROP_TRAILING_SEP is set.
 | 
			
		||||
		 *
 | 
			
		||||
		 *   dst > non_root_start:
 | 
			
		||||
		 *     there is at least 1 character after the root directory 
 | 
			
		||||
		 *     part.
 | 
			
		||||
		 *   MIO_IS_PATH_SEP(dst[-1]):
 | 
			
		||||
		 *     the canonical path ends with a separator.
 | 
			
		||||
		 *   MIO_IS_PATH_SEP(ptr[-1]):
 | 
			
		||||
		 *     the origial path ends with a separator.
 | 
			
		||||
		 */
 | 
			
		||||
		dst[-1] = '\0';
 | 
			
		||||
		canon_len = dst - canon - 1;
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		/* just null-terminate the canonical path normally */
 | 
			
		||||
		dst[0] = '\0';	
 | 
			
		||||
		canon_len = dst - canon;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (canon_len <= 0) 
 | 
			
		||||
	{
 | 
			
		||||
		if (!(flags & MIO_CANON_UCSTR_PATH_EMPTY_SINGLE_DOT))
 | 
			
		||||
		{
 | 
			
		||||
			/* when resolving to a single dot, a trailing separator is not
 | 
			
		||||
			 * retained though the orignal path name contains it. */
 | 
			
		||||
			canon[0] = '.';
 | 
			
		||||
			canon[1] = '\0';
 | 
			
		||||
			canon_len = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		/* drop a traling separator if the last segment is 
 | 
			
		||||
		 * double slashes */
 | 
			
		||||
 | 
			
		||||
		int adj_base_len = 3;
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
		if (is_drive && !has_root) 
 | 
			
		||||
		{
 | 
			
		||||
			/* A path like A:..\\\ need some adjustment for
 | 
			
		||||
			 * finalization below. */
 | 
			
		||||
			adj_base_len += 2;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (canon_len == adj_base_len)
 | 
			
		||||
		{
 | 
			
		||||
			/* i don't have to retain a trailing separator
 | 
			
		||||
			 * if the last segment is double slashes because 
 | 
			
		||||
			 * the double slahses indicate a directory obviously */
 | 
			
		||||
			if (canon[canon_len-3] == '.' &&
 | 
			
		||||
			    canon[canon_len-2] == '.' &&
 | 
			
		||||
			    MIO_IS_PATH_SEP(canon[canon_len-1]))
 | 
			
		||||
			{
 | 
			
		||||
				canon[--canon_len] = '\0';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (canon_len > adj_base_len)
 | 
			
		||||
		{
 | 
			
		||||
			if (MIO_IS_PATH_SEP(canon[canon_len-4]) &&
 | 
			
		||||
			    canon[canon_len-3] == '.' &&
 | 
			
		||||
			    canon[canon_len-2] == '.' &&
 | 
			
		||||
			    MIO_IS_PATH_SEP(canon[canon_len-1]))
 | 
			
		||||
			{
 | 
			
		||||
				canon[--canon_len] = '\0';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return canon_len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------ */
 | 
			
		||||
/*  MBS IMPLEMENTATION                                                */
 | 
			
		||||
/* ------------------------------------------------------------------ */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
int mio_is_bcstr_path_absolute (const mio_bch_t* path)
 | 
			
		||||
{
 | 
			
		||||
	if (MIO_IS_PATH_SEP(path[0])) return 1;
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	/* a drive like c:tmp is absolute in positioning the drive.
 | 
			
		||||
	 * but the path within the drive is kind of relative */
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path)) return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_is_bcstr_path_drive (const mio_bch_t* path)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path)) return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_is_bcstr_path_drive_absolute (const mio_bch_t* path)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path) && MIO_IS_PATH_SEP(path[2])) return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mio_is_bcstr_path_drive_current (const mio_bch_t* path)
 | 
			
		||||
{
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(path) && path[2] == '\0') return 1;
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
mio_oow_t mio_canon_bcstr_path (const mio_bch_t* path, mio_bch_t* canon, int flags)
 | 
			
		||||
{
 | 
			
		||||
	const mio_bch_t* ptr;
 | 
			
		||||
	mio_bch_t* dst;
 | 
			
		||||
	mio_bch_t* non_root_start;
 | 
			
		||||
	int has_root = 0;
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	int is_drive = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	mio_oow_t canon_len;
 | 
			
		||||
 | 
			
		||||
	if (path[0] == '\0') 
 | 
			
		||||
	{
 | 
			
		||||
		/* if the source is empty, no translation is needed */
 | 
			
		||||
		canon[0] = '\0';
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ptr = path;
 | 
			
		||||
	dst = canon;
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
	if (MIO_IS_PATH_DRIVE(ptr))
 | 
			
		||||
	{
 | 
			
		||||
		/* handle drive letter */
 | 
			
		||||
		*dst++ = *ptr++; /* drive letter */
 | 
			
		||||
		*dst++ = *ptr++; /* colon */
 | 
			
		||||
 | 
			
		||||
		is_drive = 1;
 | 
			
		||||
		if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
		{
 | 
			
		||||
			*dst++ = *ptr++; /* root directory */
 | 
			
		||||
			has_root = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
	{
 | 
			
		||||
		*dst++ = *ptr++; /* root directory */
 | 
			
		||||
		has_root = 1;
 | 
			
		||||
 | 
			
		||||
	#if defined(_WIN32)
 | 
			
		||||
		/* handle UNC path for Windows */
 | 
			
		||||
		if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
		{
 | 
			
		||||
			*dst++ = *ptr++;
 | 
			
		||||
 | 
			
		||||
			if (MIO_IS_PATH_SEP_OR_NIL(*ptr))
 | 
			
		||||
			{
 | 
			
		||||
				/* if there is another separator after \\,
 | 
			
		||||
				 * it's not an UNC path. */
 | 
			
		||||
				dst--;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				/* if it starts with \\, process host name */
 | 
			
		||||
				do { *dst++ = *ptr++; } while (!MIO_IS_PATH_SEP_OR_NIL(*ptr));
 | 
			
		||||
				if (MIO_IS_PATH_SEP(*ptr)) *dst++ = *ptr++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	#endif
 | 
			
		||||
	}
 | 
			
		||||
#else
 | 
			
		||||
	if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
	{
 | 
			
		||||
		*dst++ = *ptr++; /* root directory */
 | 
			
		||||
		has_root = 1;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* non_root_start points to the beginning of the canonicalized 
 | 
			
		||||
	 * path excluding the root directory part. */
 | 
			
		||||
	non_root_start = dst;
 | 
			
		||||
 | 
			
		||||
	do
 | 
			
		||||
	{
 | 
			
		||||
		const mio_bch_t* seg;
 | 
			
		||||
		mio_oow_t seglen;
 | 
			
		||||
 | 
			
		||||
		/* skip duplicate separators */
 | 
			
		||||
		while (MIO_IS_PATH_SEP(*ptr)) ptr++;
 | 
			
		||||
 | 
			
		||||
		/* end of path reached */
 | 
			
		||||
		if (*ptr == '\0') break;
 | 
			
		||||
 | 
			
		||||
		/* find the next segment */
 | 
			
		||||
		seg = ptr;
 | 
			
		||||
		while (!MIO_IS_PATH_SEP_OR_NIL(*ptr)) ptr++;
 | 
			
		||||
		seglen = ptr - seg;
 | 
			
		||||
 | 
			
		||||
		/* handle the segment */
 | 
			
		||||
		if (seglen == 1 && seg[0] == '.')
 | 
			
		||||
		{
 | 
			
		||||
			/* eat up . */
 | 
			
		||||
		}
 | 
			
		||||
		else if (!(flags & MIO_CANON_BCSTR_PATH_KEEP_DOUBLE_DOTS) &&
 | 
			
		||||
		         seglen == 2 && seg[0] == '.' && seg[1] == '.')
 | 
			
		||||
		{
 | 
			
		||||
			/* eat up the previous segment */
 | 
			
		||||
			mio_bch_t* tmp;
 | 
			
		||||
 | 
			
		||||
			tmp = dst;
 | 
			
		||||
			if (tmp > non_root_start) 
 | 
			
		||||
			{
 | 
			
		||||
				/* there is a previous segment. */
 | 
			
		||||
 | 
			
		||||
				tmp--; /* skip the separator just before .. */
 | 
			
		||||
 | 
			
		||||
				/* find the beginning of the previous segment */
 | 
			
		||||
				while (tmp > non_root_start)
 | 
			
		||||
				{
 | 
			
		||||
					tmp--;
 | 
			
		||||
					if (MIO_IS_PATH_SEP(*tmp)) 
 | 
			
		||||
					{
 | 
			
		||||
						tmp++; /* position it next to the separator */
 | 
			
		||||
						break; 
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (has_root)
 | 
			
		||||
			{
 | 
			
		||||
				/*
 | 
			
		||||
				 * Eat up the previous segment if it exists.
 | 
			
		||||
				 *
 | 
			
		||||
				 * If it doesn't exist, tmp == dst so dst = tmp
 | 
			
		||||
				 * keeps dst unchanged. If it exists, 
 | 
			
		||||
				 * tmp != dst. so dst = tmp changes dst.
 | 
			
		||||
				 *
 | 
			
		||||
				 * path  /abc/def/..
 | 
			
		||||
				 *                ^ ^
 | 
			
		||||
				 *              seg ptr
 | 
			
		||||
				 *
 | 
			
		||||
				 * canon /abc/def/
 | 
			
		||||
				 *            ^   ^   
 | 
			
		||||
				 *           tmp dst
 | 
			
		||||
				 */
 | 
			
		||||
				dst = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				mio_oow_t prevlen;
 | 
			
		||||
 | 
			
		||||
				prevlen = dst - tmp;
 | 
			
		||||
 | 
			
		||||
				if (/*tmp == non_root_start &&*/ prevlen == 0)
 | 
			
		||||
				{
 | 
			
		||||
					/* there is no previous segment */
 | 
			
		||||
					goto normal;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (prevlen == 3 && tmp[0] == '.' && tmp[1] == '.') 
 | 
			
		||||
				{
 | 
			
		||||
					/* nothing to eat away because the previous segment is ../
 | 
			
		||||
					 *
 | 
			
		||||
					 * path  ../../
 | 
			
		||||
					 *          ^ ^
 | 
			
		||||
					 *        seg ptr
 | 
			
		||||
					 *
 | 
			
		||||
					 * canon ../
 | 
			
		||||
					 *       ^  ^
 | 
			
		||||
					 *      tmp dst
 | 
			
		||||
					 */
 | 
			
		||||
					goto normal;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				dst = tmp;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
		normal:
 | 
			
		||||
			while (seg < ptr) *dst++ = *seg++;
 | 
			
		||||
			if (MIO_IS_PATH_SEP(*ptr)) 
 | 
			
		||||
			{
 | 
			
		||||
				/* this segment ended with a separator */
 | 
			
		||||
				*dst++ = *seg++; /* copy the separator */
 | 
			
		||||
				ptr++; /* move forward the pointer */
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	while (1);
 | 
			
		||||
 | 
			
		||||
	if (dst > non_root_start && MIO_IS_PATH_SEP(dst[-1]) && 
 | 
			
		||||
	    ((flags & MIO_CANON_BCSTR_PATH_DROP_TRAILING_SEP) || !MIO_IS_PATH_SEP(ptr[-1]))) 
 | 
			
		||||
	{
 | 
			
		||||
		/* if the canoncal path composed so far ends with a separator
 | 
			
		||||
		 * and the original path didn't end with the separator, delete
 | 
			
		||||
		 * the ending separator. 
 | 
			
		||||
		 * also delete it if MIO_CANON_BCSTR_PATH_DROP_TRAILING_SEP is set.
 | 
			
		||||
		 *
 | 
			
		||||
		 *   dst > non_root_start:
 | 
			
		||||
		 *     there is at least 1 character after the root directory 
 | 
			
		||||
		 *     part.
 | 
			
		||||
		 *   MIO_IS_PATH_SEP(dst[-1]):
 | 
			
		||||
		 *     the canonical path ends with a separator.
 | 
			
		||||
		 *   MIO_IS_PATH_SEP(ptr[-1]):
 | 
			
		||||
		 *     the origial path ends with a separator.
 | 
			
		||||
		 */
 | 
			
		||||
		dst[-1] = '\0';
 | 
			
		||||
		canon_len = dst - canon - 1;
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		/* just null-terminate the canonical path normally */
 | 
			
		||||
		dst[0] = '\0';
 | 
			
		||||
		canon_len = dst - canon;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (canon_len <= 0) 
 | 
			
		||||
	{
 | 
			
		||||
		if (!(flags & MIO_CANON_BCSTR_PATH_EMPTY_SINGLE_DOT))
 | 
			
		||||
		{
 | 
			
		||||
			/* when resolving to a single dot, a trailing separator is not
 | 
			
		||||
			 * retained though the orignal path name contains it. */
 | 
			
		||||
			canon[0] = '.';
 | 
			
		||||
			canon[1] = '\0';
 | 
			
		||||
			canon_len = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else 
 | 
			
		||||
	{
 | 
			
		||||
		/* drop a traling separator if the last segment is 
 | 
			
		||||
		 * double slashes */
 | 
			
		||||
 | 
			
		||||
		int adj_base_len = 3;
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
 | 
			
		||||
		if (is_drive && !has_root) 
 | 
			
		||||
		{
 | 
			
		||||
			/* A path like A:..\\\ need some adjustment for
 | 
			
		||||
			 * finalization below. */
 | 
			
		||||
			adj_base_len += 2;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (canon_len == adj_base_len)
 | 
			
		||||
		{
 | 
			
		||||
			/* i don't have to retain a trailing separator
 | 
			
		||||
			 * if the last segment is double slashes because 
 | 
			
		||||
			 * the double slahses indicate a directory obviously */
 | 
			
		||||
			if (canon[canon_len-3] == '.' &&
 | 
			
		||||
			    canon[canon_len-2] == '.' &&
 | 
			
		||||
			    MIO_IS_PATH_SEP(canon[canon_len-1]))
 | 
			
		||||
			{
 | 
			
		||||
				canon[--canon_len] = '\0';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else if (canon_len > adj_base_len)
 | 
			
		||||
		{
 | 
			
		||||
			if (MIO_IS_PATH_SEP(canon[canon_len-4]) &&
 | 
			
		||||
			    canon[canon_len-3] == '.' &&
 | 
			
		||||
			    canon[canon_len-2] == '.' &&
 | 
			
		||||
			    MIO_IS_PATH_SEP(canon[canon_len-1]))
 | 
			
		||||
			{
 | 
			
		||||
				canon[--canon_len] = '\0';
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return canon_len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user