Fossil SCM

Rudimentary support for [wikipedia:interwiki_links|interwiki links].

drh 2020-08-22 20:23 trunk
Commit 3ca23edc8fe05300dc31dbc3d771e39a1a7fa99bde0712ffd799e2ac6dff3dcc
1 file changed +96
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1197,10 +1197,100 @@
11971197
) ){
11981198
return 0;
11991199
}
12001200
return wikiOverrideHash;
12011201
}
1202
+
1203
+/*
1204
+** If zTarget is an interwiki link, return a pointer to a URL for that
1205
+** link target in memory obtained from fossil_malloc(). If zTarget is
1206
+** not a valid interwiki link, return NULL.
1207
+**
1208
+** An interwiki link target is of the form:
1209
+**
1210
+** Code:PageName
1211
+**
1212
+** "Code" is a brief code that describes the intended target wiki.
1213
+** Codes are assigned by "intermap:*" entries in the CONFIG table.
1214
+** The link is only valid if there exists an try in the CONFIG table
1215
+** that matches "intermap:Code".
1216
+**
1217
+** Each value of each intermap:Code entry in the CONFIG table is a JSON
1218
+** object with the following fields:
1219
+**
1220
+** {
1221
+** "base": Base URL for the remote site.
1222
+** "hash": Append this to "base" for Hash targets.
1223
+** "wiki": Append this to "base" for Wiki targets.
1224
+** }
1225
+**
1226
+** If the remote wiki is Fossil, then the correct value for "hash"
1227
+** is "/info/" and the correct value for "wiki" is "/wiki?name=".
1228
+** If (for example) Wikipedia is the remote, then "hash" should be
1229
+** omitted and the correct value for "wiki" is "/wiki/".
1230
+**
1231
+** PageName is link name of the target wiki. Several different forms
1232
+** of PageName are recognized.
1233
+**
1234
+** Path If PageName is empty or begins with a "/" character, then
1235
+** it is a pathname that is appended to "base".
1236
+**
1237
+** Hash If PageName is a hexadecimal string of 4 or more
1238
+** characters, then PageName is appended to "hash" which
1239
+** is then appended to "base".
1240
+**
1241
+** Wiki If PageName does not start with "/" and it is
1242
+** not a hexadecimal string of 4 or more characters, then
1243
+** PageName is appended to "wiki" and that combination is
1244
+** appended to "base".
1245
+**
1246
+** See https://en.wikipedia.org/wiki/Interwiki_links for further information
1247
+** on interwiki links.
1248
+*/
1249
+static char *wiki_is_interwiki(const char *zTarget){
1250
+ int nCode;
1251
+ int i;
1252
+ const char *zPage;
1253
+ int nPage;
1254
+ char *zUrl = 0;
1255
+ Stmt q;
1256
+ for(i=0; zTarget[i] && zTarget[i]!=':'; i++){}
1257
+ if( zTarget[i]==0 ) return 0;
1258
+ nCode = i;
1259
+ if( nCode==4 && strncmp(zTarget,"wiki",4)==0 ) return 0;
1260
+ zPage = zTarget + nCode + 1;
1261
+ nPage = (int)strlen(zPage);
1262
+ db_prepare(&q,
1263
+ "SELECT json_extract(value,'$.base'),"
1264
+ " json_extract(value,'$.hash'),"
1265
+ " json_extract(value,'$.wiki')"
1266
+ " FROM config WHERE name=lower('interwiki:%.*q')",
1267
+ nCode, zTarget);
1268
+ while( db_step(&q)==SQLITE_ROW ){
1269
+ const char *zBase = db_column_text(&q,0);
1270
+ if( zBase==0 || zBase[0]==0 ) break;
1271
+ if( nPage==0 || zPage[0]=='/' ){
1272
+ /* Path */
1273
+ zUrl = mprintf("%s%s", zBase, zPage);
1274
+ }else if( nPage>=4 && validate16(zPage,nPage) ){
1275
+ /* Hash */
1276
+ const char *zHash = db_column_text(&q,1);
1277
+ if( zHash && zHash[0] ){
1278
+ zUrl = mprintf("%s%s%s", zBase, zHash, zPage);
1279
+ }
1280
+ }else{
1281
+ /* Wiki */
1282
+ const char *zWiki = db_column_text(&q,2);
1283
+ if( zWiki && zWiki[0] ){
1284
+ zUrl = mprintf("%s%s%s", zBase, zWiki, zPage);
1285
+ }
1286
+ }
1287
+ break;
1288
+ }
1289
+ db_finalize(&q);
1290
+ return zUrl;
1291
+}
12021292
12031293
/*
12041294
** Resolve a hyperlink. The zTarget argument is the content of the [...]
12051295
** in the wiki. Append to the output string whatever text is appropriate
12061296
** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
@@ -1230,10 +1320,12 @@
12301320
**
12311321
** [WikiPageName]
12321322
** [wiki:WikiPageName]
12331323
**
12341324
** [2010-02-27 07:13]
1325
+**
1326
+** [InterMap:Link] -> Interwiki link
12351327
*/
12361328
void wiki_resolve_hyperlink(
12371329
Blob *pOut, /* Write the HTML output here */
12381330
int mFlags, /* Rendering option flags */
12391331
const char *zTarget, /* Hyperlink target; text within [...] */
@@ -1244,10 +1336,11 @@
12441336
){
12451337
const char *zTerm = "</a>";
12461338
const char *z;
12471339
char *zExtra = 0;
12481340
const char *zExtraNS = 0;
1341
+ char *zRemote = 0;
12491342
12501343
if( zTitle ){
12511344
zExtra = mprintf(" title='%h'", zTitle);
12521345
zExtraNS = zExtra+1;
12531346
}
@@ -1303,10 +1396,13 @@
13031396
blob_appendf(pOut, "%z[",xhref(zExtraNS, "%R/info/%s", zTarget));
13041397
zTerm = "]</a>";
13051398
}else{
13061399
zTerm = "";
13071400
}
1401
+ }else if( (zRemote = wiki_is_interwiki(zTarget))!=0 ){
1402
+ blob_appendf(pOut, "<a href=\"%z\"%s>", zRemote, zExtra);
1403
+ zTerm = "</a>";
13081404
}else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){
13091405
/* The link is to a valid wiki page name */
13101406
const char *zOverride = wiki_is_overridden(zTarget);
13111407
if( zOverride ){
13121408
blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra);
13131409
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1197,10 +1197,100 @@
1197 ) ){
1198 return 0;
1199 }
1200 return wikiOverrideHash;
1201 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1202
1203 /*
1204 ** Resolve a hyperlink. The zTarget argument is the content of the [...]
1205 ** in the wiki. Append to the output string whatever text is appropriate
1206 ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
@@ -1230,10 +1320,12 @@
1230 **
1231 ** [WikiPageName]
1232 ** [wiki:WikiPageName]
1233 **
1234 ** [2010-02-27 07:13]
 
 
1235 */
1236 void wiki_resolve_hyperlink(
1237 Blob *pOut, /* Write the HTML output here */
1238 int mFlags, /* Rendering option flags */
1239 const char *zTarget, /* Hyperlink target; text within [...] */
@@ -1244,10 +1336,11 @@
1244 ){
1245 const char *zTerm = "</a>";
1246 const char *z;
1247 char *zExtra = 0;
1248 const char *zExtraNS = 0;
 
1249
1250 if( zTitle ){
1251 zExtra = mprintf(" title='%h'", zTitle);
1252 zExtraNS = zExtra+1;
1253 }
@@ -1303,10 +1396,13 @@
1303 blob_appendf(pOut, "%z[",xhref(zExtraNS, "%R/info/%s", zTarget));
1304 zTerm = "]</a>";
1305 }else{
1306 zTerm = "";
1307 }
 
 
 
1308 }else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){
1309 /* The link is to a valid wiki page name */
1310 const char *zOverride = wiki_is_overridden(zTarget);
1311 if( zOverride ){
1312 blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra);
1313
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1197,10 +1197,100 @@
1197 ) ){
1198 return 0;
1199 }
1200 return wikiOverrideHash;
1201 }
1202
1203 /*
1204 ** If zTarget is an interwiki link, return a pointer to a URL for that
1205 ** link target in memory obtained from fossil_malloc(). If zTarget is
1206 ** not a valid interwiki link, return NULL.
1207 **
1208 ** An interwiki link target is of the form:
1209 **
1210 ** Code:PageName
1211 **
1212 ** "Code" is a brief code that describes the intended target wiki.
1213 ** Codes are assigned by "intermap:*" entries in the CONFIG table.
1214 ** The link is only valid if there exists an try in the CONFIG table
1215 ** that matches "intermap:Code".
1216 **
1217 ** Each value of each intermap:Code entry in the CONFIG table is a JSON
1218 ** object with the following fields:
1219 **
1220 ** {
1221 ** "base": Base URL for the remote site.
1222 ** "hash": Append this to "base" for Hash targets.
1223 ** "wiki": Append this to "base" for Wiki targets.
1224 ** }
1225 **
1226 ** If the remote wiki is Fossil, then the correct value for "hash"
1227 ** is "/info/" and the correct value for "wiki" is "/wiki?name=".
1228 ** If (for example) Wikipedia is the remote, then "hash" should be
1229 ** omitted and the correct value for "wiki" is "/wiki/".
1230 **
1231 ** PageName is link name of the target wiki. Several different forms
1232 ** of PageName are recognized.
1233 **
1234 ** Path If PageName is empty or begins with a "/" character, then
1235 ** it is a pathname that is appended to "base".
1236 **
1237 ** Hash If PageName is a hexadecimal string of 4 or more
1238 ** characters, then PageName is appended to "hash" which
1239 ** is then appended to "base".
1240 **
1241 ** Wiki If PageName does not start with "/" and it is
1242 ** not a hexadecimal string of 4 or more characters, then
1243 ** PageName is appended to "wiki" and that combination is
1244 ** appended to "base".
1245 **
1246 ** See https://en.wikipedia.org/wiki/Interwiki_links for further information
1247 ** on interwiki links.
1248 */
1249 static char *wiki_is_interwiki(const char *zTarget){
1250 int nCode;
1251 int i;
1252 const char *zPage;
1253 int nPage;
1254 char *zUrl = 0;
1255 Stmt q;
1256 for(i=0; zTarget[i] && zTarget[i]!=':'; i++){}
1257 if( zTarget[i]==0 ) return 0;
1258 nCode = i;
1259 if( nCode==4 && strncmp(zTarget,"wiki",4)==0 ) return 0;
1260 zPage = zTarget + nCode + 1;
1261 nPage = (int)strlen(zPage);
1262 db_prepare(&q,
1263 "SELECT json_extract(value,'$.base'),"
1264 " json_extract(value,'$.hash'),"
1265 " json_extract(value,'$.wiki')"
1266 " FROM config WHERE name=lower('interwiki:%.*q')",
1267 nCode, zTarget);
1268 while( db_step(&q)==SQLITE_ROW ){
1269 const char *zBase = db_column_text(&q,0);
1270 if( zBase==0 || zBase[0]==0 ) break;
1271 if( nPage==0 || zPage[0]=='/' ){
1272 /* Path */
1273 zUrl = mprintf("%s%s", zBase, zPage);
1274 }else if( nPage>=4 && validate16(zPage,nPage) ){
1275 /* Hash */
1276 const char *zHash = db_column_text(&q,1);
1277 if( zHash && zHash[0] ){
1278 zUrl = mprintf("%s%s%s", zBase, zHash, zPage);
1279 }
1280 }else{
1281 /* Wiki */
1282 const char *zWiki = db_column_text(&q,2);
1283 if( zWiki && zWiki[0] ){
1284 zUrl = mprintf("%s%s%s", zBase, zWiki, zPage);
1285 }
1286 }
1287 break;
1288 }
1289 db_finalize(&q);
1290 return zUrl;
1291 }
1292
1293 /*
1294 ** Resolve a hyperlink. The zTarget argument is the content of the [...]
1295 ** in the wiki. Append to the output string whatever text is appropriate
1296 ** for opening the hyperlink. Write into zClose[0...nClose-1] text that will
@@ -1230,10 +1320,12 @@
1320 **
1321 ** [WikiPageName]
1322 ** [wiki:WikiPageName]
1323 **
1324 ** [2010-02-27 07:13]
1325 **
1326 ** [InterMap:Link] -> Interwiki link
1327 */
1328 void wiki_resolve_hyperlink(
1329 Blob *pOut, /* Write the HTML output here */
1330 int mFlags, /* Rendering option flags */
1331 const char *zTarget, /* Hyperlink target; text within [...] */
@@ -1244,10 +1336,11 @@
1336 ){
1337 const char *zTerm = "</a>";
1338 const char *z;
1339 char *zExtra = 0;
1340 const char *zExtraNS = 0;
1341 char *zRemote = 0;
1342
1343 if( zTitle ){
1344 zExtra = mprintf(" title='%h'", zTitle);
1345 zExtraNS = zExtra+1;
1346 }
@@ -1303,10 +1396,13 @@
1396 blob_appendf(pOut, "%z[",xhref(zExtraNS, "%R/info/%s", zTarget));
1397 zTerm = "]</a>";
1398 }else{
1399 zTerm = "";
1400 }
1401 }else if( (zRemote = wiki_is_interwiki(zTarget))!=0 ){
1402 blob_appendf(pOut, "<a href=\"%z\"%s>", zRemote, zExtra);
1403 zTerm = "</a>";
1404 }else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){
1405 /* The link is to a valid wiki page name */
1406 const char *zOverride = wiki_is_overridden(zTarget);
1407 if( zOverride ){
1408 blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra);
1409

Keyboard Shortcuts

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