Index: dmake/make.c =================================================================== RCS file: /cvs/tools/dmake/make.c,v retrieving revision 1.7.2.8 diff -u -r1.7.2.8 make.c --- dmake/make.c 9 Nov 2006 18:16:33 -0000 1.7.2.8 +++ dmake/make.c 9 Nov 2006 20:15:47 -0000 @@ -307,6 +307,8 @@ for(dp=CeMeToo(cp); dp; dp=dp->cl_next) { tcp = dp->cl_prq; if( push ) { + /* If we changed the directory because of .SETDIR write Pwd into + * tcp->ce_dir so that it holds an absolute path. */ if( !(tcp->ce_attr & A_POOL) && tcp->ce_dir ) FREE( tcp->ce_dir ); tcp->ce_dir = _pool_lookup(Pwd); tcp->ce_attr |= A_SETDIR|A_POOL; @@ -716,6 +718,7 @@ * of the target. */ if( push ) { char *dir = nsetdirroot ? nsetdirroot->ce_dir : Makedir; + /* get relative path from current SETDIR to new SETDIR. */ char *pref = _prefix(dir,tcp->ce_dir); char *nname = Build_path(pref, tcp->ce_fname); @@ -773,34 +776,73 @@ static char * -_prefix( pfx, pat ) +_prefix( pfx, pat )/* +===================== + Return the relative path from pfx to pat. Both paths have to be absolute + paths. If the paths are on different resources or drives (if applicable) + return pat. */ char *pfx; char *pat; { char *cmp1=pfx; char *cmp2=pat; - char *result = DmStrDup(""); + char *result; char *up; + int first = 1; + + /* Micro optimization return immediately if pfx and pat are equal. */ + if( strcmp(pfx, pat) == 0 ) + return(DmStrDup("")); +#ifdef HAVE_DRIVE_LETTERS + /* If the drive letters are different use the abs. path. */ + if( *pfx && pfx[1] == ':' && isalpha(*pfx) + && *pat && pat[1] == ':' && isalpha(*pat) ) { + if( tolower(*pfx) != tolower(*pat) ) { + return(DmStrDup(pat)); + } + } +#endif + + /* Cut off equal leading parts of pfx, pat. Both have to be abs. paths. */ while(*pfx && *pat) { + /* skip leading dir. separators. */ pfx = DmStrSpn(cmp1, DirBrkStr); pat = DmStrSpn(cmp2, DirBrkStr); + /* Only check in the first run of the loop. Leading slashes can only + * mean POSIX paths or Windows resources (two) slashes. Drive letters + * have no leading slash. In any case, if the number of slashes are + * not equal there can be no relative path from one two the other. + * In this case return the absolute path. */ + if( first ) { + if( cmp1-pfx != cmp2-pat ) { + return(DmStrDup(pat)); + } + first = 0; + } + + /* find next dir. separator (or ""). */ cmp1 = DmStrPbrk(pfx, DirBrkStr); cmp2 = DmStrPbrk(pat, DirBrkStr); + /* if length of directory name is equal compare the strings. If equal + * go into next loop. */ if ( (cmp1-pfx) != (cmp2-pat) || strncmp(pfx,pat,cmp1-pfx) != 0 ) break; } + result = DmStrDup(""); up = DmStrJoin("..",DirSepStr,-1,FALSE); cmp1 = pfx; + /* Add "../" for each directory in pfx */ while ( *(pfx=DmStrSpn(cmp1,DirBrkStr)) != '\0' ) { cmp1 = DmStrPbrk(pfx,DirBrkStr); result = DmStrJoin(result,up,-1,TRUE); } cmp2 = pat; + /* Append each directory in pat to result. FIXME: why not append pat? */ while ( *(pat=DmStrSpn(cmp2,DirBrkStr)) != '\0' ) { char *tmp; char *x; @@ -1348,106 +1390,15 @@ $(PWD)) to the directory dmake was started up in (value of $(MAKEDIR)). */ { - char *m, *p; - char *mend, *pend; - char *mtd, *ptd; - int mleadslash, pleadslash; char *tmd; - int first = 1; - - /* Don't use Get_token because this fails on paths that contain spaces. */ - m = DmStrSpn(Makedir, DirBrkStr); - mleadslash = m - Makedir; - p = DmStrSpn(Pwd, DirBrkStr); - pleadslash = p - Pwd; - - /* leading slashes can only mean POSIX paths or Windows resources (two) - * slashes. In any case if the number of slashes are not equal there - * can be no relative path from one two the other. Use the Makedir path. */ - if(mleadslash != pleadslash) { - tmd = Makedir; - goto tmd_end; - } - /* If Makedir and Pwd are identical skip to the end. */ - for(mend=m, pend=p; *mend && *pend && *mend==*pend; mend++, pend++) - ; - if( ( ! *mend ) && ( ! *pend ) ) { - tmd = DmStrDup( "." ); - goto tmd_end; + tmd = _prefix(Pwd, Makedir); + if( *tmd ) { + Def_macro( "TMD", tmd, M_MULTI | M_EXPANDED ); + } else { + Def_macro( "TMD", ".", M_MULTI | M_EXPANDED ); } - - /* If Makedir and Pwd are not identical we will construct TMD. */ - tmd = DmStrDup( "" ); - - do { - - /* get the next top directory name */ - mend = DmStrPbrk( m, DirBrkStr ); - /* For DOSish filenames the first part might be a drive letter */ -#ifdef HAVE_DRIVE_LETTERS - if( first && *mend == ':' ) - mend++; -#endif - - mtd = DmSubStr( m, mend ); /* Free later */ - /* {m|p}end either points to a DirBrkStr member or the end of string. */ - if(*mend) mend++; - m = mend; - - pend = DmStrPbrk( p, DirBrkStr ); -#ifdef HAVE_DRIVE_LETTERS - if( first && *pend == ':' ) - pend++; -#endif - - ptd = DmSubStr( p, pend ); /* Free later */ - if(*pend) pend++; - p = pend; - - /* If tmd is started or the first difference is found continue - * constructing tmd. */ - if( *tmd || strcmp(mtd, ptd) ) { - char *tmp = 0; - - /* The following check also detects different drive letters. */ - if( first ) { /* They differ in the first component */ - FREE( tmd ); - FREE( mtd ); - FREE( ptd ); - tmd = Makedir; /* In this case use the full path */ - break; - } - - if( *ptd ) { - /* Add ".." in front of tmd if the "rest" of PWD is not "". */ - /* Build_path puts a DirSepStr behind the first parameter if - * its length is greater null, even if the second parameter - * is empty. */ - if(*tmd) - tmp = Build_path( "..", tmd ); - else - tmp = ".."; - FREE( tmd ); - tmd = DmStrDup( tmp ); - } - if( *mtd ) { - /* Add the "rest" of MAKEDIR to the end of tmd if it is not "". */ - tmp = Build_path( tmd, mtd ); - FREE( tmd ); - tmd = DmStrDup( tmp ); - } - } - - FREE( mtd ); - FREE( ptd ); - first = 0; - } while (*m || *p); - -tmd_end: - - Def_macro( "TMD", tmd, M_MULTI | M_EXPANDED ); - if( tmd != Makedir ) FREE( tmd ); + FREE( tmd ); }