Fossil SCM

Send the --from argument of the "fossil ui" command encoded as hexadecimal, to work around quoting problems on Windows. [forum:/forumpost/cfc22d41b19a1a96|Forum post cfc22d41b19a1a96].

drh 2024-12-17 12:38 trunk
Commit 593ceca27dbe17d8d7658c217a771792e3db41fbab4cba5c4cdf80be9a385748
+18
--- src/encode.c
+++ src/encode.c
@@ -729,10 +729,28 @@
729729
while( *z && n-- ){
730730
*z = zEncode[zDecode[(*z)&0x7f]&0x1f];
731731
z++;
732732
}
733733
}
734
+
735
+/*
736
+** Decode hexadecimal into a string and return the new string. Space to
737
+** hold the string is obtained from fossil_malloc() and should be released
738
+** by the caller.
739
+**
740
+** If the input is not hex, return NULL.
741
+*/
742
+char *decode16_dup(const char *zIn){
743
+ int nIn = (int)strlen(zIn);
744
+ char *zOut;
745
+ if( !validate16(zIn, nIn) ) return 0;
746
+ zOut = fossil_malloc(nIn/2+1);
747
+ decode16((const u8*)zIn, (u8*)zOut, nIn);
748
+ zOut[nIn/2] = 0;
749
+ return zOut;
750
+}
751
+
734752
735753
/*
736754
** Decode a string encoded using "quoted-printable".
737755
**
738756
** (1) "=" followed by two hex digits becomes a single
739757
--- src/encode.c
+++ src/encode.c
@@ -729,10 +729,28 @@
729 while( *z && n-- ){
730 *z = zEncode[zDecode[(*z)&0x7f]&0x1f];
731 z++;
732 }
733 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734
735 /*
736 ** Decode a string encoded using "quoted-printable".
737 **
738 ** (1) "=" followed by two hex digits becomes a single
739
--- src/encode.c
+++ src/encode.c
@@ -729,10 +729,28 @@
729 while( *z && n-- ){
730 *z = zEncode[zDecode[(*z)&0x7f]&0x1f];
731 z++;
732 }
733 }
734
735 /*
736 ** Decode hexadecimal into a string and return the new string. Space to
737 ** hold the string is obtained from fossil_malloc() and should be released
738 ** by the caller.
739 **
740 ** If the input is not hex, return NULL.
741 */
742 char *decode16_dup(const char *zIn){
743 int nIn = (int)strlen(zIn);
744 char *zOut;
745 if( !validate16(zIn, nIn) ) return 0;
746 zOut = fossil_malloc(nIn/2+1);
747 decode16((const u8*)zIn, (u8*)zOut, nIn);
748 zOut[nIn/2] = 0;
749 return zOut;
750 }
751
752
753 /*
754 ** Decode a string encoded using "quoted-printable".
755 **
756 ** (1) "=" followed by two hex digits becomes a single
757
+8 -8
--- src/info.c
+++ src/info.c
@@ -784,17 +784,12 @@
784784
@ Changes to %h(zFile)
785785
@ </span></div>
786786
if( pCfg ){
787787
char *zFullFN;
788788
char *zHexFN;
789
- int nFullFN;
790789
zFullFN = file_canonical_name_dup(zLhs);
791
- nFullFN = (int)strlen(zFullFN);
792
- zHexFN = fossil_malloc( nFullFN*2 + 5 );
793
- zHexFN[0] = 'x';
794
- encode16((const u8*)zFullFN, (u8*)(zHexFN+1), nFullFN);
795
- zHexFN[1+nFullFN*2] = 0;
790
+ zHexFN = mprintf("x%H", zFullFN);
796791
fossil_free(zFullFN);
797792
pCfg->zLeftHash = zHexFN;
798793
text_diff(&lhs, &rhs, cgi_output_blob(), pCfg);
799794
pCfg->zLeftHash = 0;
800795
fossil_free(zHexFN);
@@ -819,11 +814,14 @@
819814
**
820815
** If the "exbase=PATH" query parameter is provided, then the diff shown
821816
** uses the files in PATH as the baseline. This is the same as using
822817
** the "--from PATH" argument to the "fossil diff" command-line. In fact,
823818
** when using "fossil ui --from PATH", the --from argument becomes the value
824
-** of the exbase query parameter for the start page.
819
+** of the exbase query parameter for the start page. Note that if PATH
820
+** is a pure hexadecimal string, it is decoded first before being used as
821
+** the pathname. Real pathnames should contain at least one directory
822
+** separator character.
825823
**
826824
** Other query parameters related to diffs are also accepted.
827825
*/
828826
void ckout_page(void){
829827
int vid;
@@ -861,18 +859,20 @@
861859
}
862860
render_checkin_context(vid, 0, 0, 0);
863861
@ <hr>
864862
zExBase = P("exbase");
865863
if( zExBase && zExBase[0] ){
866
- char *zCBase = file_canonical_name_dup(zExBase);
864
+ char *zPath = decode16_dup(zExBase);
865
+ char *zCBase = file_canonical_name_dup(zPath?zPath:zExBase);
867866
if( nHome && strncmp(zCBase, zHome, nHome)==0 && zCBase[nHome]=='/' ){
868867
@ <p>Using external baseline: ~%h(zCBase+nHome)</p>
869868
}else{
870869
@ <p>Using external baseline: %h(zCBase)</p>
871870
}
872871
ckout_external_base_diff(vid, zCBase);
873872
fossil_free(zCBase);
873
+ fossil_free(zPath);
874874
}else{
875875
ckout_normal_diff(vid);
876876
}
877877
style_finish_page();
878878
}
879879
--- src/info.c
+++ src/info.c
@@ -784,17 +784,12 @@
784 @ Changes to %h(zFile)
785 @ </span></div>
786 if( pCfg ){
787 char *zFullFN;
788 char *zHexFN;
789 int nFullFN;
790 zFullFN = file_canonical_name_dup(zLhs);
791 nFullFN = (int)strlen(zFullFN);
792 zHexFN = fossil_malloc( nFullFN*2 + 5 );
793 zHexFN[0] = 'x';
794 encode16((const u8*)zFullFN, (u8*)(zHexFN+1), nFullFN);
795 zHexFN[1+nFullFN*2] = 0;
796 fossil_free(zFullFN);
797 pCfg->zLeftHash = zHexFN;
798 text_diff(&lhs, &rhs, cgi_output_blob(), pCfg);
799 pCfg->zLeftHash = 0;
800 fossil_free(zHexFN);
@@ -819,11 +814,14 @@
819 **
820 ** If the "exbase=PATH" query parameter is provided, then the diff shown
821 ** uses the files in PATH as the baseline. This is the same as using
822 ** the "--from PATH" argument to the "fossil diff" command-line. In fact,
823 ** when using "fossil ui --from PATH", the --from argument becomes the value
824 ** of the exbase query parameter for the start page.
 
 
 
825 **
826 ** Other query parameters related to diffs are also accepted.
827 */
828 void ckout_page(void){
829 int vid;
@@ -861,18 +859,20 @@
861 }
862 render_checkin_context(vid, 0, 0, 0);
863 @ <hr>
864 zExBase = P("exbase");
865 if( zExBase && zExBase[0] ){
866 char *zCBase = file_canonical_name_dup(zExBase);
 
867 if( nHome && strncmp(zCBase, zHome, nHome)==0 && zCBase[nHome]=='/' ){
868 @ <p>Using external baseline: ~%h(zCBase+nHome)</p>
869 }else{
870 @ <p>Using external baseline: %h(zCBase)</p>
871 }
872 ckout_external_base_diff(vid, zCBase);
873 fossil_free(zCBase);
 
874 }else{
875 ckout_normal_diff(vid);
876 }
877 style_finish_page();
878 }
879
--- src/info.c
+++ src/info.c
@@ -784,17 +784,12 @@
784 @ Changes to %h(zFile)
785 @ </span></div>
786 if( pCfg ){
787 char *zFullFN;
788 char *zHexFN;
 
789 zFullFN = file_canonical_name_dup(zLhs);
790 zHexFN = mprintf("x%H", zFullFN);
 
 
 
 
791 fossil_free(zFullFN);
792 pCfg->zLeftHash = zHexFN;
793 text_diff(&lhs, &rhs, cgi_output_blob(), pCfg);
794 pCfg->zLeftHash = 0;
795 fossil_free(zHexFN);
@@ -819,11 +814,14 @@
814 **
815 ** If the "exbase=PATH" query parameter is provided, then the diff shown
816 ** uses the files in PATH as the baseline. This is the same as using
817 ** the "--from PATH" argument to the "fossil diff" command-line. In fact,
818 ** when using "fossil ui --from PATH", the --from argument becomes the value
819 ** of the exbase query parameter for the start page. Note that if PATH
820 ** is a pure hexadecimal string, it is decoded first before being used as
821 ** the pathname. Real pathnames should contain at least one directory
822 ** separator character.
823 **
824 ** Other query parameters related to diffs are also accepted.
825 */
826 void ckout_page(void){
827 int vid;
@@ -861,18 +859,20 @@
859 }
860 render_checkin_context(vid, 0, 0, 0);
861 @ <hr>
862 zExBase = P("exbase");
863 if( zExBase && zExBase[0] ){
864 char *zPath = decode16_dup(zExBase);
865 char *zCBase = file_canonical_name_dup(zPath?zPath:zExBase);
866 if( nHome && strncmp(zCBase, zHome, nHome)==0 && zCBase[nHome]=='/' ){
867 @ <p>Using external baseline: ~%h(zCBase+nHome)</p>
868 }else{
869 @ <p>Using external baseline: %h(zCBase)</p>
870 }
871 ckout_external_base_diff(vid, zCBase);
872 fossil_free(zCBase);
873 fossil_free(zPath);
874 }else{
875 ckout_normal_diff(vid);
876 }
877 style_finish_page();
878 }
879
+1 -1
--- src/main.c
+++ src/main.c
@@ -3297,11 +3297,11 @@
32973297
}
32983298
zInitPage = find_option("page", "p", 1);
32993299
if( zInitPage && zInitPage[0]=='/' ) zInitPage++;
33003300
zFossilCmd = find_option("fossilcmd", 0, 1);
33013301
if( zFrom && zInitPage==0 ){
3302
- zInitPage = mprintf("ckout?exbase=%T", zFrom);
3302
+ zInitPage = mprintf("ckout?exbase=%H", zFrom);
33033303
}
33043304
}
33053305
zNotFound = find_option("notfound", 0, 1);
33063306
allowRepoList = find_option("repolist",0,0)!=0;
33073307
if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1;
33083308
--- src/main.c
+++ src/main.c
@@ -3297,11 +3297,11 @@
3297 }
3298 zInitPage = find_option("page", "p", 1);
3299 if( zInitPage && zInitPage[0]=='/' ) zInitPage++;
3300 zFossilCmd = find_option("fossilcmd", 0, 1);
3301 if( zFrom && zInitPage==0 ){
3302 zInitPage = mprintf("ckout?exbase=%T", zFrom);
3303 }
3304 }
3305 zNotFound = find_option("notfound", 0, 1);
3306 allowRepoList = find_option("repolist",0,0)!=0;
3307 if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1;
3308
--- src/main.c
+++ src/main.c
@@ -3297,11 +3297,11 @@
3297 }
3298 zInitPage = find_option("page", "p", 1);
3299 if( zInitPage && zInitPage[0]=='/' ) zInitPage++;
3300 zFossilCmd = find_option("fossilcmd", 0, 1);
3301 if( zFrom && zInitPage==0 ){
3302 zInitPage = mprintf("ckout?exbase=%H", zFrom);
3303 }
3304 }
3305 zNotFound = find_option("notfound", 0, 1);
3306 allowRepoList = find_option("repolist",0,0)!=0;
3307 if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1;
3308
+13 -1
--- src/printf.c
+++ src/printf.c
@@ -105,10 +105,11 @@
105105
Use %!j to include double-quotes around it. */
106106
#define etSHELLESC 26 /* Escape a filename for use in a shell command: %$
107107
See blob_append_escaped_arg() for details
108108
"%$" -> adds "./" prefix if necessary.
109109
"%!$" -> omits the "./" prefix. */
110
+#define etHEX 27 /* Encode a string as hexadecimal */
110111
111112
112113
/*
113114
** An "etByte" is an 8-bit unsigned value.
114115
*/
@@ -142,11 +143,11 @@
142143
** NB: When modifying this table is it vital that you also update the fmtchr[]
143144
** variable to match!!!
144145
*/
145146
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
146147
static const char aPrefix[] = "-x0\000X0";
147
-static const char fmtchr[] = "dsgzqQbBWhRtTwFSjcouxXfeEGin%p/$";
148
+static const char fmtchr[] = "dsgzqQbBWhRtTwFSjcouxXfeEGin%p/$H";
148149
static const et_info fmtinfo[] = {
149150
{ 'd', 10, 1, etRADIX, 0, 0 },
150151
{ 's', 0, 4, etSTRING, 0, 0 },
151152
{ 'g', 0, 1, etGENERIC, 30, 0 },
152153
{ 'z', 0, 6, etDYNSTRING, 0, 0 },
@@ -176,10 +177,11 @@
176177
{ 'n', 0, 0, etSIZE, 0, 0 },
177178
{ '%', 0, 0, etPERCENT, 0, 0 },
178179
{ 'p', 16, 0, etPOINTER, 0, 1 },
179180
{ '/', 0, 0, etPATH, 0, 0 },
180181
{ '$', 0, 0, etSHELLESC, 0, 0 },
182
+ { 'H', 0, 0, etHEX, 0, 0 },
181183
{ etERROR, 0,0,0,0,0} /* Must be last */
182184
};
183185
#define etNINFO count(fmtinfo)
184186
185187
/*
@@ -843,10 +845,20 @@
843845
case etSHELLESC: {
844846
char *zArg = va_arg(ap, char*);
845847
blob_append_escaped_arg(pBlob, zArg, !flag_altform2);
846848
length = width = 0;
847849
break;
850
+ }
851
+ case etHEX: {
852
+ char *zArg = va_arg(ap, char*);
853
+ int szArg = (int)strlen(zArg);
854
+ int szBlob = blob_size(pBlob);
855
+ u8 *aBuf = (u8*)&blob_buffer(pBlob)[szBlob];
856
+ blob_resize(pBlob, szBlob+szArg*2+1);
857
+ encode16((const u8*)zArg, aBuf, szArg);
858
+ length = width = 0;
859
+ break;
848860
}
849861
case etERROR:
850862
buf[0] = '%';
851863
buf[1] = c;
852864
errorflag = 0;
853865
--- src/printf.c
+++ src/printf.c
@@ -105,10 +105,11 @@
105 Use %!j to include double-quotes around it. */
106 #define etSHELLESC 26 /* Escape a filename for use in a shell command: %$
107 See blob_append_escaped_arg() for details
108 "%$" -> adds "./" prefix if necessary.
109 "%!$" -> omits the "./" prefix. */
 
110
111
112 /*
113 ** An "etByte" is an 8-bit unsigned value.
114 */
@@ -142,11 +143,11 @@
142 ** NB: When modifying this table is it vital that you also update the fmtchr[]
143 ** variable to match!!!
144 */
145 static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
146 static const char aPrefix[] = "-x0\000X0";
147 static const char fmtchr[] = "dsgzqQbBWhRtTwFSjcouxXfeEGin%p/$";
148 static const et_info fmtinfo[] = {
149 { 'd', 10, 1, etRADIX, 0, 0 },
150 { 's', 0, 4, etSTRING, 0, 0 },
151 { 'g', 0, 1, etGENERIC, 30, 0 },
152 { 'z', 0, 6, etDYNSTRING, 0, 0 },
@@ -176,10 +177,11 @@
176 { 'n', 0, 0, etSIZE, 0, 0 },
177 { '%', 0, 0, etPERCENT, 0, 0 },
178 { 'p', 16, 0, etPOINTER, 0, 1 },
179 { '/', 0, 0, etPATH, 0, 0 },
180 { '$', 0, 0, etSHELLESC, 0, 0 },
 
181 { etERROR, 0,0,0,0,0} /* Must be last */
182 };
183 #define etNINFO count(fmtinfo)
184
185 /*
@@ -843,10 +845,20 @@
843 case etSHELLESC: {
844 char *zArg = va_arg(ap, char*);
845 blob_append_escaped_arg(pBlob, zArg, !flag_altform2);
846 length = width = 0;
847 break;
 
 
 
 
 
 
 
 
 
 
848 }
849 case etERROR:
850 buf[0] = '%';
851 buf[1] = c;
852 errorflag = 0;
853
--- src/printf.c
+++ src/printf.c
@@ -105,10 +105,11 @@
105 Use %!j to include double-quotes around it. */
106 #define etSHELLESC 26 /* Escape a filename for use in a shell command: %$
107 See blob_append_escaped_arg() for details
108 "%$" -> adds "./" prefix if necessary.
109 "%!$" -> omits the "./" prefix. */
110 #define etHEX 27 /* Encode a string as hexadecimal */
111
112
113 /*
114 ** An "etByte" is an 8-bit unsigned value.
115 */
@@ -142,11 +143,11 @@
143 ** NB: When modifying this table is it vital that you also update the fmtchr[]
144 ** variable to match!!!
145 */
146 static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
147 static const char aPrefix[] = "-x0\000X0";
148 static const char fmtchr[] = "dsgzqQbBWhRtTwFSjcouxXfeEGin%p/$H";
149 static const et_info fmtinfo[] = {
150 { 'd', 10, 1, etRADIX, 0, 0 },
151 { 's', 0, 4, etSTRING, 0, 0 },
152 { 'g', 0, 1, etGENERIC, 30, 0 },
153 { 'z', 0, 6, etDYNSTRING, 0, 0 },
@@ -176,10 +177,11 @@
177 { 'n', 0, 0, etSIZE, 0, 0 },
178 { '%', 0, 0, etPERCENT, 0, 0 },
179 { 'p', 16, 0, etPOINTER, 0, 1 },
180 { '/', 0, 0, etPATH, 0, 0 },
181 { '$', 0, 0, etSHELLESC, 0, 0 },
182 { 'H', 0, 0, etHEX, 0, 0 },
183 { etERROR, 0,0,0,0,0} /* Must be last */
184 };
185 #define etNINFO count(fmtinfo)
186
187 /*
@@ -843,10 +845,20 @@
845 case etSHELLESC: {
846 char *zArg = va_arg(ap, char*);
847 blob_append_escaped_arg(pBlob, zArg, !flag_altform2);
848 length = width = 0;
849 break;
850 }
851 case etHEX: {
852 char *zArg = va_arg(ap, char*);
853 int szArg = (int)strlen(zArg);
854 int szBlob = blob_size(pBlob);
855 u8 *aBuf = (u8*)&blob_buffer(pBlob)[szBlob];
856 blob_resize(pBlob, szBlob+szArg*2+1);
857 encode16((const u8*)zArg, aBuf, szArg);
858 length = width = 0;
859 break;
860 }
861 case etERROR:
862 buf[0] = '%';
863 buf[1] = c;
864 errorflag = 0;
865

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button