| | @@ -127,12 +127,13 @@ |
| 127 | 127 | ** query parameter is present. If ci= is missing, the union of files |
| 128 | 128 | ** across all check-ins is shown. |
| 129 | 129 | ** |
| 130 | 130 | ** Query parameters: |
| 131 | 131 | ** |
| 132 | +** ci=LABEL Show only files in this check-in. Optional. |
| 132 | 133 | ** name=PATH Directory to display. Optional. Top-level if missing |
| 133 | | -** ci=LABEL Show only files in this check-in. Optional. |
| 134 | +** re=REGEXP Show only files matching REGEXP |
| 134 | 135 | ** type=TYPE TYPE=flat: use this display |
| 135 | 136 | ** TYPE=tree: use the /tree display instead |
| 136 | 137 | ** noreadme Do not attempt to display the README file. |
| 137 | 138 | */ |
| 138 | 139 | void page_dir(void){ |
| | @@ -150,10 +151,12 @@ |
| 150 | 151 | int linkTip = 1; |
| 151 | 152 | HQuery sURI; |
| 152 | 153 | int isSymbolicCI = 0; /* ci= is symbolic name, not a hash prefix */ |
| 153 | 154 | int isBranchCI = 0; /* True if ci= refers to a branch name */ |
| 154 | 155 | char *zHeader = 0; |
| 156 | + const char *zRegexp; /* The re= query parameter */ |
| 157 | + char *zMatch; /* Extra title text describing the match */ |
| 155 | 158 | |
| 156 | 159 | if( zCI && strlen(zCI)==0 ){ zCI = 0; } |
| 157 | 160 | if( strcmp(PD("type","flat"),"tree")==0 ){ page_tree(); return; } |
| 158 | 161 | login_check_credentials(); |
| 159 | 162 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| | @@ -192,10 +195,17 @@ |
| 192 | 195 | if( zCI ){ |
| 193 | 196 | zHeader = mprintf("Files in %s/ of %s", zD, zCI); |
| 194 | 197 | }else{ |
| 195 | 198 | zHeader = mprintf("All File in %s/", zD); |
| 196 | 199 | } |
| 200 | + } |
| 201 | + zRegexp = P("re"); |
| 202 | + if( zRegexp ){ |
| 203 | + zHeader = mprintf("%z matching \"%s\"", zHeader, zRegexp); |
| 204 | + zMatch = mprintf(" matching \"%h\"", zRegexp); |
| 205 | + }else{ |
| 206 | + zMatch = ""; |
| 197 | 207 | } |
| 198 | 208 | style_header("%s", zHeader); |
| 199 | 209 | fossil_free(zHeader); |
| 200 | 210 | style_adunit_config(ADUNIT_RIGHT_OK); |
| 201 | 211 | sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0, |
| | @@ -217,16 +227,19 @@ |
| 217 | 227 | @ <h2>Files in the top-level directory \ |
| 218 | 228 | zPrefix = ""; |
| 219 | 229 | } |
| 220 | 230 | if( zCI ){ |
| 221 | 231 | if( fossil_strcmp(zCI,"tip")==0 ){ |
| 222 | | - @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a></h2> |
| 232 | + @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a>\ |
| 233 | + @ %s(zMatch)</h2> |
| 223 | 234 | }else if( isBranchCI ){ |
| 224 | 235 | @ from the %z(href("%R/info?name=%T",zCI))latest check-in</a> \ |
| 225 | | - @ of branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a></h2> |
| 236 | + @ of branch %z(href("%R/timeline?r=%T",zCI))%h(zCI)</a>\ |
| 237 | + @ %s(zMatch)</h2> |
| 226 | 238 | }else { |
| 227 | | - @ of check-in %z(href("%R/info?name=%T",zCI))%h(zCI)</a></h2> |
| 239 | + @ of check-in %z(href("%R/info?name=%T",zCI))%h(zCI)</a>\ |
| 240 | + @ %s(zMatch)</h2> |
| 228 | 241 | } |
| 229 | 242 | zSubdirLink = mprintf("%R/dir?ci=%T&name=%T", zCI, zPrefix); |
| 230 | 243 | if( nD==0 ){ |
| 231 | 244 | style_submenu_element("File Ages", "%R/fileage?name=%T", zCI); |
| 232 | 245 | } |
| | @@ -302,10 +315,18 @@ |
| 302 | 315 | db_multi_exec( |
| 303 | 316 | "INSERT OR IGNORE INTO localfiles" |
| 304 | 317 | " SELECT pathelement(name,0), NULL FROM filename" |
| 305 | 318 | ); |
| 306 | 319 | } |
| 320 | + |
| 321 | + /* If the re=REGEXP query parameter is present, filter out names that |
| 322 | + ** do not match the pattern */ |
| 323 | + if( zRegexp ){ |
| 324 | + db_multi_exec( |
| 325 | + "DELETE FROM localfiles WHERE x NOT REGEXP %Q", zRegexp |
| 326 | + ); |
| 327 | + } |
| 307 | 328 | |
| 308 | 329 | /* Generate a multi-column table listing the contents of zD[] |
| 309 | 330 | ** directory. |
| 310 | 331 | */ |
| 311 | 332 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 312 | 333 | |