| | @@ -989,5 +989,196 @@ |
| 989 | 989 | fossil_fatal("METHOD should be one of:" |
| 990 | 990 | " export import merge pull push reset"); |
| 991 | 991 | } |
| 992 | 992 | configure_rebuild(); |
| 993 | 993 | } |
| 994 | + |
| 995 | + |
| 996 | +/* |
| 997 | +** COMMAND: test-var-list |
| 998 | +** |
| 999 | +** Usage: %fossil test-var-list ?PATTERN? ?--unset? ?--mtime? |
| 1000 | +** |
| 1001 | +** Show the content of the CONFIG table in a repository. If PATTERN is |
| 1002 | +** specified, then only show the entries that match that glob pattern. |
| 1003 | +** Last modification time is shown if the --mtime option is present. |
| 1004 | +** |
| 1005 | +** If the --unset option is included, then entries are deleted rather than |
| 1006 | +** being displayed. WARNING! This cannot be undone. Be sure you know what |
| 1007 | +** you are doing! The --unset option only works if there is a PATTERN. |
| 1008 | +** Probably you should run the command once without --unset to make sure |
| 1009 | +** you know exactly what is being deleted. |
| 1010 | +** |
| 1011 | +** If not in an open check-out, use the -R REPO option to specify a |
| 1012 | +** a repository. |
| 1013 | +*/ |
| 1014 | +void test_var_list_cmd(void){ |
| 1015 | + Stmt q; |
| 1016 | + int i, j; |
| 1017 | + const char *zPattern = 0; |
| 1018 | + int doUnset; |
| 1019 | + int showMtime; |
| 1020 | + Blob sql; |
| 1021 | + Blob ans; |
| 1022 | + unsigned char zTrans[1000]; |
| 1023 | + |
| 1024 | + doUnset = find_option("unset",0,0)!=0; |
| 1025 | + showMtime = find_option("mtime",0,0)!=0; |
| 1026 | + db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 1027 | + verify_all_options(); |
| 1028 | + if( g.argc>=3 ){ |
| 1029 | + zPattern = g.argv[2]; |
| 1030 | + } |
| 1031 | + blob_init(&sql,0,0); |
| 1032 | + blob_appendf(&sql, "SELECT name, value, datetime(mtime,'unixepoch')" |
| 1033 | + " FROM config"); |
| 1034 | + if( zPattern ){ |
| 1035 | + blob_appendf(&sql, " WHERE name GLOB %Q", zPattern); |
| 1036 | + } |
| 1037 | + if( showMtime ){ |
| 1038 | + blob_appendf(&sql, " ORDER BY mtime, name"); |
| 1039 | + }else{ |
| 1040 | + blob_appendf(&sql, " ORDER BY name"); |
| 1041 | + } |
| 1042 | + db_prepare(&q, "%s", blob_str(&sql)/*safe-for-%s*/); |
| 1043 | + blob_reset(&sql); |
| 1044 | +#define MX_VAL 40 |
| 1045 | +#define MX_NM 28 |
| 1046 | +#define MX_LONGNM 60 |
| 1047 | + while( db_step(&q)==SQLITE_ROW ){ |
| 1048 | + const char *zName = db_column_text(&q,0); |
| 1049 | + int nName = db_column_bytes(&q,0); |
| 1050 | + const char *zValue = db_column_text(&q,1); |
| 1051 | + int szValue = db_column_bytes(&q,1); |
| 1052 | + const char *zMTime = db_column_text(&q,2); |
| 1053 | + for(i=j=0; j<MX_VAL && zValue[i]; i++){ |
| 1054 | + unsigned char c = (unsigned char)zValue[i]; |
| 1055 | + if( c>=' ' && c<='~' ){ |
| 1056 | + zTrans[j++] = c; |
| 1057 | + }else{ |
| 1058 | + zTrans[j++] = '\\'; |
| 1059 | + if( c=='\n' ){ |
| 1060 | + zTrans[j++] = 'n'; |
| 1061 | + }else if( c=='\r' ){ |
| 1062 | + zTrans[j++] = 'r'; |
| 1063 | + }else if( c=='\t' ){ |
| 1064 | + zTrans[j++] = 't'; |
| 1065 | + }else{ |
| 1066 | + zTrans[j++] = '0' + ((c>>6)&7); |
| 1067 | + zTrans[j++] = '0' + ((c>>3)&7); |
| 1068 | + zTrans[j++] = '0' + (c&7); |
| 1069 | + } |
| 1070 | + } |
| 1071 | + } |
| 1072 | + zTrans[j] = 0; |
| 1073 | + if( i<szValue ){ |
| 1074 | + sqlite3_snprintf(sizeof(zTrans)-j, (char*)zTrans+j, "...+%d", szValue-i); |
| 1075 | + j += (int)strlen((char*)zTrans+j); |
| 1076 | + } |
| 1077 | + if( showMtime ){ |
| 1078 | + fossil_print("%s:%*s%s\n", zName, 58-nName, "", zMTime); |
| 1079 | + }else if( nName<MX_NM-2 ){ |
| 1080 | + fossil_print("%s:%*s%s\n", zName, MX_NM-1-nName, "", zTrans); |
| 1081 | + }else if( nName<MX_LONGNM-2 && j<10 ){ |
| 1082 | + fossil_print("%s:%*s%s\n", zName, MX_LONGNM-1-nName, "", zTrans); |
| 1083 | + }else{ |
| 1084 | + fossil_print("%s:\n%*s%s\n", zName, MX_NM, "", zTrans); |
| 1085 | + } |
| 1086 | + } |
| 1087 | + db_finalize(&q); |
| 1088 | + if( zPattern && doUnset ){ |
| 1089 | + prompt_user("Delete all of the above? (y/N)? ", &ans); |
| 1090 | + if( blob_str(&ans)[0]=='y' || blob_str(&ans)[0]=='Y' ){ |
| 1091 | + db_multi_exec("DELETE FROM config WHERE name GLOB %Q", zPattern); |
| 1092 | + } |
| 1093 | + blob_reset(&ans); |
| 1094 | + } |
| 1095 | +} |
| 1096 | + |
| 1097 | +/* |
| 1098 | +** COMMAND: test-var-get |
| 1099 | +** |
| 1100 | +** Usage: %fossil test-var-get VAR ?FILE? |
| 1101 | +** |
| 1102 | +** Write the text of the VAR variable into FILE. If FILE is "-" |
| 1103 | +** or is omitted then output goes to standard output. VAR can be a |
| 1104 | +** GLOB pattern. |
| 1105 | +** |
| 1106 | +** If not in an open check-out, use the -R REPO option to specify a |
| 1107 | +** a repository. |
| 1108 | +*/ |
| 1109 | +void test_var_get_cmd(void){ |
| 1110 | + const char *zVar; |
| 1111 | + const char *zFile; |
| 1112 | + int n; |
| 1113 | + Blob x; |
| 1114 | + db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 1115 | + verify_all_options(); |
| 1116 | + if( g.argc<3 ){ |
| 1117 | + usage("VAR ?FILE?"); |
| 1118 | + } |
| 1119 | + zVar = g.argv[2]; |
| 1120 | + zFile = g.argc>=4 ? g.argv[3] : "-"; |
| 1121 | + n = db_int(0, "SELECT count(*) FROM config WHERE name GLOB %Q", zVar); |
| 1122 | + if( n==0 ){ |
| 1123 | + fossil_fatal("no match for %Q", zVar); |
| 1124 | + } |
| 1125 | + if( n>1 ){ |
| 1126 | + fossil_fatal("multiple matches: %s", |
| 1127 | + db_text(0, "SELECT group_concat(quote(name),', ') FROM (" |
| 1128 | + " SELECT name FROM config WHERE name GLOB %Q ORDER BY 1)", |
| 1129 | + zVar)); |
| 1130 | + } |
| 1131 | + blob_init(&x,0,0); |
| 1132 | + db_blob(&x, "SELECT value FROM config WHERE name GLOB %Q", zVar); |
| 1133 | + blob_write_to_file(&x, zFile); |
| 1134 | +} |
| 1135 | + |
| 1136 | +/* |
| 1137 | +** COMMAND: test-var-set |
| 1138 | +** |
| 1139 | +** Usage: %fossil test-var-set VAR ?VALUE? ?--file FILE? |
| 1140 | +** |
| 1141 | +** Store VALUE or the content of FILE (exactly one of which must be |
| 1142 | +** supplied) into variable VAR. Use a FILE of "-" to read from |
| 1143 | +** standard input. |
| 1144 | +** |
| 1145 | +** WARNING: changing the value of a variable can interfere with the |
| 1146 | +** operation of Fossil. Be sure you know what you are doing. |
| 1147 | +** |
| 1148 | +** Use "--blob FILE" instead of "--file FILE" to load a binary blob |
| 1149 | +** such as a GIF. |
| 1150 | +*/ |
| 1151 | +void test_var_set_cmd(void){ |
| 1152 | + const char *zVar; |
| 1153 | + const char *zFile; |
| 1154 | + const char *zBlob; |
| 1155 | + Blob x; |
| 1156 | + Stmt ins; |
| 1157 | + zFile = find_option("file",0,1); |
| 1158 | + zBlob = find_option("blob",0,1); |
| 1159 | + db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 1160 | + verify_all_options(); |
| 1161 | + if( g.argc<3 || (zFile==0 && zBlob==0 && g.argc<4) ){ |
| 1162 | + usage("VAR ?VALUE? ?--file FILE?"); |
| 1163 | + } |
| 1164 | + zVar = g.argv[2]; |
| 1165 | + if( zFile ){ |
| 1166 | + if( zBlob ) fossil_fatal("cannot do both --file or --blob"); |
| 1167 | + blob_read_from_file(&x, zFile); |
| 1168 | + }else if( zBlob ){ |
| 1169 | + blob_read_from_file(&x, zBlob); |
| 1170 | + }else{ |
| 1171 | + blob_init(&x,g.argv[3],-1); |
| 1172 | + } |
| 1173 | + db_prepare(&ins, |
| 1174 | + "REPLACE INTO config(name,value,mtime)" |
| 1175 | + "VALUES(%Q,:val,now())", zVar); |
| 1176 | + if( zBlob ){ |
| 1177 | + db_bind_blob(&ins, ":val", &x); |
| 1178 | + }else{ |
| 1179 | + db_bind_text(&ins, ":val", blob_str(&x)); |
| 1180 | + } |
| 1181 | + db_step(&ins); |
| 1182 | + db_finalize(&ins); |
| 1183 | + blob_reset(&x); |
| 1184 | +} |
| 994 | 1185 | |