e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
1b10db2002-10-08Martin Nilsson 
2f8a602001-06-10Henrik Grubbström (Grubba) /* * Combine path template. * */
8e06782001-06-07Fredrik Hübinette (Hubbe) #undef IS_SEP
81ffaa2003-12-18Marcus Comstedt #undef IS_ANY_SEP
8e06782001-06-07Fredrik Hübinette (Hubbe) #undef IS_ABS #undef IS_ROOT
224c952004-05-01Martin Stjernholm #undef COMBINE_PATH
8e06782001-06-07Fredrik Hübinette (Hubbe) #undef APPEND_PATH
81ffaa2003-12-18Marcus Comstedt #undef CHAR_CURRENT #undef CHAR_ROOT
8e06782001-06-07Fredrik Hübinette (Hubbe)  #define COMBINE_PATH_DEBUG 0 #ifdef UNIX_COMBINE_PATH #define IS_SEP(X) ( (X)=='/' )
67b9422016-06-17Henrik Grubbström (Grubba) #define IS_ABS(X, L) ((((L) > 0) && IS_SEP(INDEX_PCHARP((X),0)))?1:0)
8e06782001-06-07Fredrik Hübinette (Hubbe) #define APPEND_PATH append_path_unix
224c952004-05-01Martin Stjernholm #define COMBINE_PATH combine_path_unix
81ffaa2003-12-18Marcus Comstedt #define CHAR_CURRENT '.' #define CHAR_ROOT '/'
8e06782001-06-07Fredrik Hübinette (Hubbe) #endif /* UNIX_COMBINE_PATH */ #ifdef NT_COMBINE_PATH #define IS_SEP(X) ( (X) == '/' || (X) == '\\' )
67b9422016-06-17Henrik Grubbström (Grubba) static int find_absolute(PCHARP s, ptrdiff_t len)
8e06782001-06-07Fredrik Hübinette (Hubbe) { int c0=INDEX_PCHARP(s,0); int c1=c0?INDEX_PCHARP(s,1):0;
c21f4a2009-10-25Martin Stjernholm  /* The following used to use isalpha(c0), but it apparently can * index out-of-bound memory in the msvc 9.0 crt when given 16-bit * char values (known to occur with 0x20ac, at least). Besides, a * drive letter is limited to a..z, so this is faster and more * correct. */ if(((c0 >= 'A' && c0 <= 'Z') || (c0 >= 'a' && c0 <= 'z')) &&
67b9422016-06-17Henrik Grubbström (Grubba)  c1==':' && IS_SEP(INDEX_PCHARP(s,2)) && (len >= 3))
8e06782001-06-07Fredrik Hübinette (Hubbe)  return 3;
67b9422016-06-17Henrik Grubbström (Grubba)  if(IS_SEP(c0) && IS_SEP(c1) && (len >= 2))
8e06782001-06-07Fredrik Hübinette (Hubbe)  { int l;
dd10722001-09-24Fredrik Hübinette (Hubbe)  for(l=2;INDEX_PCHARP(s,l) && !IS_SEP(INDEX_PCHARP(s,l));l++);
57834d2004-01-12Marcus Comstedt  return INDEX_PCHARP(s,l)? l+1:l;
8e06782001-06-07Fredrik Hübinette (Hubbe)  } return 0; }
67b9422016-06-17Henrik Grubbström (Grubba) #define IS_ABS(X, L) find_absolute((X), (L)) #define IS_ROOT(X, L) ( (((L) > 0) && IS_SEP( INDEX_PCHARP((X),0) ))?1:0)
8e06782001-06-07Fredrik Hübinette (Hubbe)  #define APPEND_PATH append_path_nt
224c952004-05-01Martin Stjernholm #define COMBINE_PATH combine_path_nt
8e06782001-06-07Fredrik Hübinette (Hubbe) 
81ffaa2003-12-18Marcus Comstedt #define CHAR_CURRENT '.' #define CHAR_ROOT '/'
8e06782001-06-07Fredrik Hübinette (Hubbe) #endif /* NT_COMBINE_PATH */
0c95942018-01-12Stephen R. van den Berg  #ifdef AMIGAOS_COMBINE_PATH #define IS_SEP(X) ( (X)=='/' ) #define IS_ANY_SEP(X) ( (X) == '/' || (X) == ':' ) #define IS_ABS(X, L) find_absolute2((X), (L)) #define IS_ROOT(X, L) ( ((L) > 0) && ( INDEX_PCHARP((X),0) == CHAR_ROOT)?1:0) #define APPEND_PATH append_path_amigaos #define COMBINE_PATH combine_path_amigaos #define CHAR_ROOT ':' static int find_absolute2(PCHARP s, ptrdiff_t len) { int r=0, p=0; int c; while((c=INDEX_PCHARP(s,p)) && (len > 0)) { ++p; --len; if(c == CHAR_ROOT) r = p; } return r>1? r:0; } #endif /* AMIGAOS_COMBINE_PATH */
81ffaa2003-12-18Marcus Comstedt #ifndef IS_ANY_SEP #define IS_ANY_SEP(X) IS_SEP(X) #endif
8e06782001-06-07Fredrik Hübinette (Hubbe) static void APPEND_PATH(struct string_builder *s, PCHARP path, size_t len) { size_t from=0;
9ca13e2003-06-12Martin Nilsson  int tmp, abs;
8e06782001-06-07Fredrik Hübinette (Hubbe) 
13670c2015-05-25Martin Nilsson  /* First, check if path is absolute,
8e06782001-06-07Fredrik Hübinette (Hubbe)  * if so ignore anything already in 's' */
67b9422016-06-17Henrik Grubbström (Grubba)  abs=IS_ABS(MKPCHARP_STR(s->s), s->s->len); if((tmp=IS_ABS(path, len)))
8e06782001-06-07Fredrik Hübinette (Hubbe)  { s->s->len=0; s->known_shift=0; string_builder_append(s, path, tmp); from+=tmp;
57834d2004-01-12Marcus Comstedt  abs=tmp;
8e06782001-06-07Fredrik Hübinette (Hubbe)  } #ifdef IS_ROOT
67b9422016-06-17Henrik Grubbström (Grubba)  else if((tmp=IS_ROOT(path, len)))
8e06782001-06-07Fredrik Hübinette (Hubbe)  { int tmp2; s->known_shift=0;
67b9422016-06-17Henrik Grubbström (Grubba)  if((tmp2=IS_ABS(MKPCHARP_STR(s->s), s->s->len)))
8e06782001-06-07Fredrik Hübinette (Hubbe)  { s->s->len=tmp2;
57834d2004-01-12Marcus Comstedt  abs=tmp2;
8e06782001-06-07Fredrik Hübinette (Hubbe)  }else{ s->s->len=0; string_builder_append(s, path, tmp);
57834d2004-01-12Marcus Comstedt  abs=tmp;
8e06782001-06-07Fredrik Hübinette (Hubbe)  } from+=tmp; } #endif #define LAST_PUSHED() (s->s->len ? index_shared_string(s->s,s->s->len-1) : 0) #define PUSH(X) string_builder_putchar(s,(X))
2f8a602001-06-10Henrik Grubbström (Grubba)  /* Ensure s ends with a separator. */
81ffaa2003-12-18Marcus Comstedt  if(s->s->len && !IS_ANY_SEP(LAST_PUSHED()))
8e06782001-06-07Fredrik Hübinette (Hubbe)  PUSH('/');
279f6a2001-06-11Henrik Grubbström (Grubba)  if (!len) return;
81ffaa2003-12-18Marcus Comstedt #ifdef CHAR_CURRENT
2f8a602001-06-10Henrik Grubbström (Grubba)  /* Remove initial "./" if any. */
913b262001-06-10Henrik Grubbström (Grubba)  if(s->s->len==2)
8e06782001-06-07Fredrik Hübinette (Hubbe)  { PCHARP to=MKPCHARP_STR(s->s);
81ffaa2003-12-18Marcus Comstedt  if(INDEX_PCHARP(to, 0) == CHAR_CURRENT)
8e06782001-06-07Fredrik Hübinette (Hubbe)  { s->s->len=0; s->known_shift=0; } }
81ffaa2003-12-18Marcus Comstedt #endif
8e06782001-06-07Fredrik Hübinette (Hubbe)  while(1) { #if COMBINE_PATH_DEBUG > 1
67b9422016-06-17Henrik Grubbström (Grubba)  /* s->s->str[s->s->len]=0; */ fprintf(stderr, "combine_path(2), TO: \"%s\"[%d]\n", s->s->str, s->s->len); fprintf(stderr, "combine_path(2), FROM (%d): \"%s\"[%d]\n", from, path.ptr+from, len - from);
8e06782001-06-07Fredrik Hübinette (Hubbe) #endif if(IS_SEP(LAST_PUSHED())) {
0c95942018-01-12Stephen R. van den Berg #ifdef AMIGAOS_COMBINE_PATH if(from<len && INDEX_PCHARP(path, from) == '/' && s->s->len>1 && !IS_ANY_SEP(index_shared_string(s->s,s->s->len-2))) { /* Handle "//" */ int tmp=s->s->len-2; while(tmp>0 && !IS_ANY_SEP(index_shared_string(s->s,tmp-1))) --tmp; s->s->len=tmp; s->known_shift=0; from++; continue; } #else /* !AMIGAOS_COMBINE_PATH */
8e06782001-06-07Fredrik Hübinette (Hubbe)  while(s->s->len && IS_SEP(LAST_PUSHED())) s->s->len--; PUSH('/'); if(from<len && INDEX_PCHARP(path, from) == '.') { int c3; #if COMBINE_PATH_DEBUG > 0
67b9422016-06-17Henrik Grubbström (Grubba)  /* s->s->str[s->s->len]=0; */ fprintf(stderr, "combine_path(0), TO: \"%s\"[%d]\n", s->s->str, s->s->len); fprintf(stderr, "combine_path(0), FROM (%d): \"%s\"[%d]\n", from, path.ptr+from, len - from);
8e06782001-06-07Fredrik Hübinette (Hubbe) #endif switch(INDEX_PCHARP(path, from+1)) { case '.': c3=INDEX_PCHARP(path, from+2); if(IS_SEP(c3) || !c3) {
2f8a602001-06-10Henrik Grubbström (Grubba)  /* Handle "..". */
8e06782001-06-07Fredrik Hübinette (Hubbe)  int tmp=s->s->len-1;
2f8a602001-06-10Henrik Grubbström (Grubba)  if (tmp) { while(--tmp>=0) if(IS_SEP(index_shared_string(s->s, tmp))) break; tmp++; } else if (IS_SEP(index_shared_string(s->s, 0))) { tmp++; }
13670c2015-05-25Martin Nilsson 
57834d2004-01-12Marcus Comstedt  if (tmp < abs) tmp = abs; else if ((tmp+1 < s->s->len) && (index_shared_string(s->s,tmp)=='.') &&
13670c2015-05-25Martin Nilsson  (index_shared_string(s->s,tmp+1)=='.') &&
57834d2004-01-12Marcus Comstedt  ( (tmp+2 == s->s->len) || IS_SEP(index_shared_string(s->s,tmp+2)))) break; from+=(c3? 3:2);
8e06782001-06-07Fredrik Hübinette (Hubbe)  s->s->len=tmp; s->known_shift=0; #if COMBINE_PATH_DEBUG > 0
67b9422016-06-17Henrik Grubbström (Grubba)  /* s->s->str[s->s->len]=0; */ fprintf(stderr,"combine_path(1), TO: %s[%d]\n", s->s->str, s->s->len); fprintf(stderr,"combine_path(1), FROM (%d): %s[%d]\n", from, path.ptr+from, len-from);
8e06782001-06-07Fredrik Hübinette (Hubbe) #endif continue; } break;
13670c2015-05-25Martin Nilsson 
8e06782001-06-07Fredrik Hübinette (Hubbe)  case 0: case '/': #ifdef NT_COMBINE_PATH case '\\': #endif
2f8a602001-06-10Henrik Grubbström (Grubba)  /* Handle ".". */ from++; continue;
8e06782001-06-07Fredrik Hübinette (Hubbe)  } }
0c95942018-01-12Stephen R. van den Berg #endif /* !AMIGAOS_COMBINE_PATH */
8e06782001-06-07Fredrik Hübinette (Hubbe)  } if(from>=len) break; PUSH(INDEX_PCHARP(path, from++)); }
57834d2004-01-12Marcus Comstedt  if((s->s->len > 1) && (s->s->len > abs) &&
8e06782001-06-07Fredrik Hübinette (Hubbe)  !IS_SEP(INDEX_PCHARP(path, from-1)) && IS_SEP(LAST_PUSHED())) s->s->len--;
13670c2015-05-25Martin Nilsson 
8e06782001-06-07Fredrik Hübinette (Hubbe)  if(!s->s->len) { if(abs) {
81ffaa2003-12-18Marcus Comstedt  PUSH(CHAR_ROOT); #ifdef CHAR_CURRENT
8e06782001-06-07Fredrik Hübinette (Hubbe)  }else{
81ffaa2003-12-18Marcus Comstedt  PUSH(CHAR_CURRENT);
57834d2004-01-12Marcus Comstedt  if(IS_SEP(INDEX_PCHARP(path, from-1))) PUSH('/');
81ffaa2003-12-18Marcus Comstedt #endif
8e06782001-06-07Fredrik Hübinette (Hubbe)  } } }
224c952004-05-01Martin Stjernholm #define F_FUNC(X) PIKE_CONCAT(f_,X) void F_FUNC(COMBINE_PATH)(INT32 args)
8e06782001-06-07Fredrik Hübinette (Hubbe) { int e; int root=0; struct string_builder ret; ONERROR tmp;
d103422018-08-05Martin Nilsson  check_all_args(NULL,args,
224c952004-05-01Martin Stjernholm  BIT_STRING, BIT_STRING | BIT_MANY | BIT_VOID, 0);
8e06782001-06-07Fredrik Hübinette (Hubbe)  init_string_builder(&ret, 0); SET_ONERROR(tmp, free_string_builder, &ret);
67b9422016-06-17Henrik Grubbström (Grubba) #if COMBINE_PATH_DEBUG > 0 for(e=0; e < args; e++) { fprintf(stderr, "combine_path(), Arg #%d: \"%s\"[%d bytes]\n", e, Pike_sp[e-args].u.string->str, Pike_sp[e-args].u.string->len); } #endif #if COMBINE_PATH_DEBUG > 5 fprintf(stderr, "combine_path(), Empty: \"%s\"[%d bytes]\n", ret.s->str, ret.s->len); fprintf(stderr, "combine_path(), Empty+1: \"%s\"\n", ret.s->str+1); #endif
8e06782001-06-07Fredrik Hübinette (Hubbe)  for(e=args-1;e>root;e--) {
67b9422016-06-17Henrik Grubbström (Grubba)  if(IS_ABS(MKPCHARP_STR(Pike_sp[e-args].u.string), Pike_sp[e-args].u.string->len))
8e06782001-06-07Fredrik Hübinette (Hubbe)  { root=e; break; } } APPEND_PATH(&ret, MKPCHARP_STR(Pike_sp[root-args].u.string), Pike_sp[root-args].u.string->len); root++;
67b9422016-06-17Henrik Grubbström (Grubba) #if COMBINE_PATH_DEBUG > 1 fprintf(stderr, "combine_path(), ret: \"%s\"[%d] (root: %d)\n", ret.s->str, ret.s->len, root); #endif
8e06782001-06-07Fredrik Hübinette (Hubbe) #ifdef IS_ROOT for(e=args-1;e>root;e--) {
67b9422016-06-17Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[e-args]) != T_STRING) continue; if(IS_ROOT(MKPCHARP_STR(Pike_sp[e-args].u.string), Pike_sp[e-args].u.string->len))
8e06782001-06-07Fredrik Hübinette (Hubbe)  { root=e; break; } }
67b9422016-06-17Henrik Grubbström (Grubba) #if COMBINE_PATH_DEBUG > 1 fprintf(stderr, "combine_path(), root: %d\n", root); #endif
8e06782001-06-07Fredrik Hübinette (Hubbe) #endif
13670c2015-05-25Martin Nilsson 
8e06782001-06-07Fredrik Hübinette (Hubbe)  while(root<args) {
67b9422016-06-17Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[root-args]) != T_STRING) continue; #if COMBINE_PATH_DEBUG > 0 fprintf(stderr, "combine_path(), Appending \"%s\"[%d] root: %d\n", Pike_sp[root-args].u.string->str, Pike_sp[root-args].u.string->len, root); #endif
8e06782001-06-07Fredrik Hübinette (Hubbe)  APPEND_PATH(&ret, MKPCHARP_STR(Pike_sp[root-args].u.string), Pike_sp[root-args].u.string->len); root++; } UNSET_ONERROR(tmp); pop_n_elems(args); push_string(finish_string_builder(&ret)); }
67b9422016-06-17Henrik Grubbström (Grubba) #undef COMBINE_PATH_DEBUG
8e06782001-06-07Fredrik Hübinette (Hubbe) #undef UNIX_COMBINE_PATH #undef NT_COMBINE_PATH
0c95942018-01-12Stephen R. van den Berg #undef AMIGAOS_COMBINE_PATH