Browse Source

Adding scat and moving to legacy webfs and wikifs

Signed-off-by: Álvaro Jurado <elbingmiss@gmail.com>
Álvaro Jurado 6 years ago
parent
commit
31e409b1d8

+ 1 - 0
sys/src/cmd/build.json

@@ -62,6 +62,7 @@
 			"rio/rio.json",
 			"sam/build.json",
 			"samterm/build.json",
+			"scat/build.json",
 			"tarsplit/build.json",
 			"tbl/build.json",
 			"troff2html/build.json",

+ 1 - 0
sys/src/cmd/map/map.h

@@ -31,6 +31,7 @@ struct coord {
 struct place {
 	struct coord nlat;
 	struct coord wlon;
+	struct coord elon; /* For cmd/scat */
 };
 
 typedef int (*proj)(struct place *, double *, double *);

+ 14 - 0
sys/src/cmd/scat/build.json

@@ -0,0 +1,14 @@
+{
+	"scat": {
+		"Include": [
+			"../cmd.json"
+		],
+		"Cflags": [
+			"-I$HARVEY/sys/src/cmd/map"
+		],
+		"Install": "/$ARCH/bin/",
+		"SourceFiles": [
+			"*.c"
+		]
+	}
+}

+ 321 - 321
sys/src/cmd/scat/desc.c

@@ -8,329 +8,329 @@
  */
 
 char *desctab[][2]={
-	"!!!",	"(magnificent or otherwise interesting object)",
-	"!!",	"(superb)",
-	"!",	"(remarkable)",
-	"1st",	"first",
-	"2nd",	"second",
-	"3rd",	"third",
-	"4th",	"fourth",
-	"5th",	"fifth",
-	"6th",	"sixth",
-	"7th",	"seventh",
-	"8th",	"eighth",
-	"9th",	"ninth",
-	"B",	"bright",
-	"Borealis",	"Borealis",
-	"C",	"compressed",
-	"Car",	"Car",
-	"Cas",	"Cas",
-	"Cen",	"Cen",
-	"Cl",	"cluster",
-	"Cyg",	"Cyg",
-	"D",	"double",
-	"Dra",	"Dra",
-	"Dumbbell",	"Dumbbell",
-	"E",	"extended",
-	"F",	"faint",
-	"L",	"large",
-	"Lyra",	"Lyra",
-	"M",	"(in the) middle",
-	"Merope",	"Merope",
-	"Milky",	"Milky",
-	"Mon",	"Mon",
-	"N",	"(to a) nucleus",
-	"Neb",	"Nebula",
-	"Nor",	"Nor",
-	"Nucl",	"nucleus",
-	"Nuclei",	"nuclei",
-	"P",	"poor in stars",
-	"PN",	"planetary nebula",
-	"Polarissima",	"Polarissima",
-	"Praesepe",	"Praesepe",
-	"Psc",	"Psc",
-	"R",	"round",
-	"RA",	"RA",
-	"RR",	"exactly round",
-	"Ri",	"rich in stars",
-	"S",	"small",
-	"Sco",	"Sco",
-	"S*",	"small star",
-	"Way",	"Way",
-	"ab",	"about",
-	"about",	"about",
-	"alm",	"almost",
-	"alpha",	"α",
-	"am",	"among",
-	"annul",	"annular",
-	"att",	"attached",
-	"b",	"brighter",
-	"beautiful",	"beautiful",
-	"bet",	"between",
-	"beta",	"β",
-	"bf",	"brightest to f side",
-	"biN",	"binuclear",
-	"bifid",	"bifid",
-	"bifurcated",	"bifurcated",
-	"black",	"black",
-	"blue",	"blue",
-	"bn",	"brightest to n side",
-	"border",	"border",
-	"bp",	"brightest to p side",
-	"branch",	"branch",
-	"branched",	"branched",
-	"branches",	"branches",
-	"bright",	"bright",
-	"brighter",	"brighter",
-	"brightest",	"brightest",
-	"brightness",	"brightness",
-	"brush",	"brush",
-	"bs",	"brightest to s side",
-	"but",	"but",
-	"by",	"by",
-	"c",	"considerably",
-	"centre",	"centre",
-	"certain",	"certain",
-	"chev",	"chevelure",
-	"chief",	"chief",
-	"chiefly",	"chiefly",
-	"circle",	"circle",
-	"close",	"close",
-	"cloud",	"cloud",
-	"cluster",	"cluster",
-	"clusters",	"clusters",
-	"co",	"coarse, coarsely",
-	"com",	"cometic",
-	"comet",	"comet",
-	"cometary",	"cometary",
-	"comp",	"companion",
-	"condens",	"condensations",
-	"condensed",	"condensed",
-	"conn",	"connected",
-	"connected",	"connected",
-	"connecting",	"connecting",
-	"cont",	"in contact",
-	"corner",	"corner",
-	"curved",	"curved",
-	"d",	"diameter",
-	"decl",	"declination",
-	"def",	"defined",
-	"defect",	"defect",
-	"deg",	"°",
-	"delta",	"δ",
-	"dense",	"dense",
-	"densest",	"densest",
-	"descr",	"description",
-	"description",	"description",
-	"dif",	"diffuse",
-	"different",	"different",
-	"diffic",	"difficult",
-	"difficult",	"difficult",
-	"diffuse",	"diffuse",
-	"diffused",	"diffused",
-	"disc",	"disc",
-	"dist",	"distant",
-	"distant",	"distant",
-	"distinct",	"distinct",
-	"double",	"double",
-	"doubtful",	"doubtful",
-	"dozen",	"dozen",
-	"e",	"extremely",
-	"each",	"each",
-	"edge",	"edge",
-	"ee",	"most extremely",
-	"ellipt",	"elliptical",
-	"elliptic",	"elliptical",
-	"end",	"end",
-	"ends",	"ends",
-	"epsilon",	"ε",
-	"equilateral",	"equilateral",
-	"er",	"easily resolvable",
-	"eta",	"η",
-	"evidently",	"evidently",
-	"exc",	"excentric",
-	"excen",	"excentric",
-	"excent",	"excentric",
-	"excentric",	"excentric",
-	"extends",	"extends",
-	"f",	"following",
-	"faint",	"faint",
-	"fainter",	"fainter",
-	"faintest",	"faintest",
-	"falcate",	"falcate",
-	"fan",	"fan",
-	"farther",	"farther",
-	"field",	"field",
-	"fine",	"fine",
-	"forming",	"forming",
-	"forms",	"forms",
-	"found",	"found",
-	"from",	"from",
-	"g",	"gradually",
-	"gamma",	"γ",
-	"gaseous",	"gaseous",
-	"gl",	"gradually a little",
-	"glob. cl.",	"globular cluster",
-	"gr",	"group",
-	"great",	"great",
-	"greater",	"greater",
-	"group",	"group",
-	"groups",	"groups",
-	"i",	"irregular",
-	"iF",	"irregular figure",
-	"if",	"if",
-	"in",	"in",
-	"indistinct",	"indistinct",
-	"incl",	"including",
-	"inv",	"involved",
-	"iota",	"ι",
-	"irr",	"irregular",
-	"is",	"is",
-	"it",	"it",
-	"kappa",	"κ",
-	"l",	"little, long",
-	"lC",	"little compressed",
-	"lE",	"little extended",
-	"lambda",	"λ",
-	"larger",	"larger",
-	"last",	"last",
-	"lb",	"little brighter",
-	"least",	"least",
-	"like",	"like",
-	"line",	"in a line",
-	"little",	"little",
-	"long",	"long",
-	"looks",	"looks",
-	"looped",	"looped",
-	"m",	"magnitude",
-	"mE",	"much extended",
-	"mag",	"mag",
-	"makes",	"makes",
-	"many",	"many",
-	"mb",	"much brighter",
-	"more",	"more",
-	"mottled",	"mottled",
-	"mu",	"μ",
-	"mult",	"multiple",
-	"n",	"north",
-	"narrow",	"narrow",
-	"near",	"near",
-	"nearly",	"nearly",
-	"neb",	"nebula",
-	"nebs",	"nebulous",
-	"nebula",	"nebula",
-	"nebulosity",	"nebulosity",
-	"nebulous",	"nebulous",
-	"neby",	"nebulosity",
-	"nf",	"north following",
-	"no",	"no",
-	"nonexistent",	"nonexistent",
-	"not",	"not",
-	"np",	"north preceding",
-	"nr",	"near",
-	"ns",	"north-south",
-	"nu",	"ν",
-	"omega",	"ω",
-	"p",	"preceding",
-	"pB",	"pretty bright",
-	"pC",	"pretty compressed",
-	"pF",	"pretty faint",
-	"pL",	"pretty large",
-	"pR",	"pretty round",
-	"pS",	"pretty small",
-	"parallel",	"parallel",
-	"part",	"part",
-	"partly",	"partly",
-	"patch",	"patch",
-	"patches",	"patches",
-	"perhaps",	"perhaps",
-	"perpendicular",	"perpendicular",
-	"pf",	"preceding-following",
-	"pg",	"pretty gradually",
-	"photosphere",	"photosphere",
-	"pi",	"π",
-	"place",	"place",
-	"plate",	"plate",
-	"plan",	"planetary nebula",
-	"pointed",	"pointed",
-	"portion",	"portion",
-	"pos",	"position angle",
-	"possibly",	"possibly",
-	"prob",	"probably",
-	"probably",	"probably",
-	"ps",	"pretty suddenly",
-	"r",	"mottled",
-	"requires",	"requires",
-	"resolved",	"resolved",
-	"rho",	"ρ",
-	"ring",	"ring",
-	"rough",	"rough",
-	"rr",	"some stars seen",
-	"rrr",	"clearly consisting of stars",
-	"ruby",	"ruby",
-	"s",	"south",
-	"same",	"same",
-	"sb",	"suddenly brighter",
-	"sc",	"scattered",
-	"second",	"second",
-	"seems",	"seems",
-	"seen",	"seen",
-	"segment",	"segment",
-	"semi",	"semi",
-	"sev",	"several",
-	"several",	"several",
-	"sf",	"south following",
-	"shape",	"shape",
-	"shaped",	"shaped",
-	"sharp",	"sharp",
-	"sigma",	"σ",
-	"sl",	"suddenly a little",
-	"slightly",	"slightly",
-	"small",	"small",
-	"south",	"south",
-	"sp",	"south preceding",
-	"spectrum",	"spectrum",
-	"spindle",	"spindle",
-	"spir",	"spiral",
-	"spiral",	"spiral",
-	"st 9...",	"stars of mag. 9 and fainter",
-	"st 9...13",	"stars of mag. 9 to 13",
-	"st",	"stars",
-	"stell",	"stellar, pointlike",
-	"stellar",	"stellar",
-	"straight",	"straight",
-	"streak",	"streak",
-	"strongly",	"strongly",
-	"surrounded",	"surrounded",
-	"surrounds",	"surrounds",
-	"susp",	"suspected",
-	"suspected",	"suspected",
-	"tau",	"τ",
-	"theta",	"θ",
-	"trap",	"trapezium",
-	"trapez",	"trapezium",
-	"trapezium",	"trapezium",
-	"triN",	"trinuclear",
-	"v",	"very",
-	"var",	"variable",
-	"variable",	"variable",
-	"verification",	"verification",
-	"verified",	"verified",
-	"very",	"very",
-	"vl",	"very little",
-	"vm",	"very much",
-	"vs",	"very suddenly",
-	"vv",	"very very",
-	"zeta",	"ζ",
-	0,	0,
+	{"!!!",	"(magnificent or otherwise interesting object)"},
+	{"!!",	"(superb)"},
+	{"!",	"(remarkable)"},
+	{"1st",	"first"},
+	{"2nd",	"second"},
+	{"3rd",	"third"},
+	{"4th",	"fourth"},
+	{"5th",	"fifth"},
+	{"6th",	"sixth"},
+	{"7th",	"seventh"},
+	{"8th",	"eighth"},
+	{"9th",	"ninth"},
+	{"B",	"bright"},
+	{"Borealis",	"Borealis"},
+	{"C",	"compressed"},
+	{"Car",	"Car"},
+	{"Cas",	"Cas"},
+	{"Cen",	"Cen"},
+	{"Cl",	"cluster"},
+	{"Cyg",	"Cyg"},
+	{"D",	"double"},
+	{"Dra",	"Dra"},
+	{"Dumbbell",	"Dumbbell"},
+	{"E",	"extended"},
+	{"F",	"faint"},
+	{"L",	"large"},
+	{"Lyra",	"Lyra"},
+	{"M",	"(in the) middle"},
+	{"Merope",	"Merope"},
+	{"Milky",	"Milky"},
+	{"Mon",	"Mon"},
+	{"N",	"(to a) nucleus"},
+	{"Neb",	"Nebula"},
+	{"Nor",	"Nor"},
+	{"Nucl",	"nucleus"},
+	{"Nuclei",	"nuclei"},
+	{"P",	"poor in stars"},
+	{"PN",	"planetary nebula"},
+	{"Polarissima",	"Polarissima"},
+	{"Praesepe",	"Praesepe"},
+	{"Psc",	"Psc"},
+	{"R",	"round"},
+	{"RA",	"RA"},
+	{"RR",	"exactly round"},
+	{"Ri",	"rich in stars"},
+	{"S",	"small"},
+	{"Sco",	"Sco"},
+	{"S*",	"small star"},
+	{"Way",	"Way"},
+	{"ab",	"about"},
+	{"about",	"about"},
+	{"alm",	"almost"},
+	{"alpha",	"α"},
+	{"am",	"among"},
+	{"annul",	"annular"},
+	{"att",	"attached"},
+	{"b",	"brighter"},
+	{"beautiful",	"beautiful"},
+	{"bet",	"between"},
+	{"beta",	"β"},
+	{"bf",	"brightest to f side"},
+	{"biN",	"binuclear"},
+	{"bifid",	"bifid"},
+	{"bifurcated",	"bifurcated"},
+	{"black",	"black"},
+	{"blue",	"blue"},
+	{"bn",	"brightest to n side"},
+	{"border",	"border"},
+	{"bp",	"brightest to p side"},
+	{"branch",	"branch"},
+	{"branched",	"branched"},
+	{"branches",	"branches"},
+	{"bright",	"bright"},
+	{"brighter",	"brighter"},
+	{"brightest",	"brightest"},
+	{"brightness",	"brightness"},
+	{"brush",	"brush"},
+	{"bs",	"brightest to s side"},
+	{"but",	"but"},
+	{"by",	"by"},
+	{"c",	"considerably"},
+	{"centre",	"centre"},
+	{"certain",	"certain"},
+	{"chev",	"chevelure"},
+	{"chief",	"chief"},
+	{"chiefly",	"chiefly"},
+	{"circle",	"circle"},
+	{"close",	"close"},
+	{"cloud",	"cloud"},
+	{"cluster",	"cluster"},
+	{"clusters",	"clusters"},
+	{"co",	"coarse, coarsely"},
+	{"com",	"cometic"},
+	{"comet",	"comet"},
+	{"cometary",	"cometary"},
+	{"comp",	"companion"},
+	{"condens",	"condensations"},
+	{"condensed",	"condensed"},
+	{"conn",	"connected"},
+	{"connected",	"connected"},
+	{"connecting",	"connecting"},
+	{"cont",	"in contact"},
+	{"corner",	"corner"},
+	{"curved",	"curved"},
+	{"d",	"diameter"},
+	{"decl",	"declination"},
+	{"def",	"defined"},
+	{"defect",	"defect"},
+	{"deg",	"°"},
+	{"delta",	"δ"},
+	{"dense",	"dense"},
+	{"densest",	"densest"},
+	{"descr",	"description"},
+	{"description",	"description"},
+	{"dif",	"diffuse"},
+	{"different",	"different"},
+	{"diffic",	"difficult"},
+	{"difficult",	"difficult"},
+	{"diffuse",	"diffuse"},
+	{"diffused",	"diffused"},
+	{"disc",	"disc"},
+	{"dist",	"distant"},
+	{"distant",	"distant"},
+	{"distinct",	"distinct"},
+	{"double",	"double"},
+	{"doubtful",	"doubtful"},
+	{"dozen",	"dozen"},
+	{"e",	"extremely"},
+	{"each",	"each"},
+	{"edge",	"edge"},
+	{"ee",	"most extremely"},
+	{"ellipt",	"elliptical"},
+	{"elliptic",	"elliptical"},
+	{"end",	"end"},
+	{"ends",	"ends"},
+	{"epsilon",	"ε"},
+	{"equilateral",	"equilateral"},
+	{"er",	"easily resolvable"},
+	{"eta",	"η"},
+	{"evidently",	"evidently"},
+	{"exc",	"excentric"},
+	{"excen",	"excentric"},
+	{"excent",	"excentric"},
+	{"excentric",	"excentric"},
+	{"extends",	"extends"},
+	{"f",	"following"},
+	{"faint",	"faint"},
+	{"fainter",	"fainter"},
+	{"faintest",	"faintest"},
+	{"falcate",	"falcate"},
+	{"fan",	"fan"},
+	{"farther",	"farther"},
+	{"field",	"field"},
+	{"fine",	"fine"},
+	{"forming",	"forming"},
+	{"forms",	"forms"},
+	{"found",	"found"},
+	{"from",	"from"},
+	{"g",	"gradually"},
+	{"gamma",	"γ"},
+	{"gaseous",	"gaseous"},
+	{"gl",	"gradually a little"},
+	{"glob. cl.",	"globular cluster"},
+	{"gr",	"group"},
+	{"great",	"great"},
+	{"greater",	"greater"},
+	{"group",	"group"},
+	{"groups",	"groups"},
+	{"i",	"irregular"},
+	{"iF",	"irregular figure"},
+	{"if",	"if"},
+	{"in",	"in"},
+	{"indistinct",	"indistinct"},
+	{"incl",	"including"},
+	{"inv",	"involved"},
+	{"iota",	"ι"},
+	{"irr",	"irregular"},
+	{"is",	"is"},
+	{"it",	"it"},
+	{"kappa",	"κ"},
+	{"l",	"little, long"},
+	{"lC",	"little compressed"},
+	{"lE",	"little extended"},
+	{"lambda",	"λ"},
+	{"larger",	"larger"},
+	{"last",	"last"},
+	{"lb",	"little brighter"},
+	{"least",	"least"},
+	{"like",	"like"},
+	{"line",	"in a line"},
+	{"little",	"little"},
+	{"long",	"long"},
+	{"looks",	"looks"},
+	{"looped",	"looped"},
+	{"m",	"magnitude"},
+	{"mE",	"much extended"},
+	{"mag",	"mag"},
+	{"makes",	"makes"},
+	{"many",	"many"},
+	{"mb",	"much brighter"},
+	{"more",	"more"},
+	{"mottled",	"mottled"},
+	{"mu",	"μ"},
+	{"mult",	"multiple"},
+	{"n",	"north"},
+	{"narrow",	"narrow"},
+	{"near",	"near"},
+	{"nearly",	"nearly"},
+	{"neb",	"nebula"},
+	{"nebs",	"nebulous"},
+	{"nebula",	"nebula"},
+	{"nebulosity",	"nebulosity"},
+	{"nebulous",	"nebulous"},
+	{"neby",	"nebulosity"},
+	{"nf",	"north following"},
+	{"no",	"no"},
+	{"nonexistent",	"nonexistent"},
+	{"not",	"not"},
+	{"np",	"north preceding"},
+	{"nr",	"near"},
+	{"ns",	"north-south"},
+	{"nu",	"ν"},
+	{"omega",	"ω"},
+	{"p",	"preceding"},
+	{"pB",	"pretty bright"},
+	{"pC",	"pretty compressed"},
+	{"pF",	"pretty faint"},
+	{"pL",	"pretty large"},
+	{"pR",	"pretty round"},
+	{"pS",	"pretty small"},
+	{"parallel",	"parallel"},
+	{"part",	"part"},
+	{"partly",	"partly"},
+	{"patch",	"patch"},
+	{"patches",	"patches"},
+	{"perhaps",	"perhaps"},
+	{"perpendicular",	"perpendicular"},
+	{"pf",	"preceding-following"},
+	{"pg",	"pretty gradually"},
+	{"photosphere",	"photosphere"},
+	{"pi",	"π"},
+	{"place",	"place"},
+	{"plate",	"plate"},
+	{"plan",	"planetary nebula"},
+	{"pointed",	"pointed"},
+	{"portion",	"portion"},
+	{"pos",	"position angle"},
+	{"possibly",	"possibly"},
+	{"prob",	"probably"},
+	{"probably",	"probably"},
+	{"ps",	"pretty suddenly"},
+	{"r",	"mottled"},
+	{"requires",	"requires"},
+	{"resolved",	"resolved"},
+	{"rho",	"ρ"},
+	{"ring",	"ring"},
+	{"rough",	"rough"},
+	{"rr",	"some stars seen"},
+	{"rrr",	"clearly consisting of stars"},
+	{"ruby",	"ruby"},
+	{"s",	"south"},
+	{"same",	"same"},
+	{"sb",	"suddenly brighter"},
+	{"sc",	"scattered"},
+	{"second",	"second"},
+	{"seems",	"seems"},
+	{"seen",	"seen"},
+	{"segment",	"segment"},
+	{"semi",	"semi"},
+	{"sev",	"several"},
+	{"several",	"several"},
+	{"sf",	"south following"},
+	{"shape",	"shape"},
+	{"shaped",	"shaped"},
+	{"sharp",	"sharp"},
+	{"sigma",	"σ"},
+	{"sl",	"suddenly a little"},
+	{"slightly",	"slightly"},
+	{"small",	"small"},
+	{"south",	"south"},
+	{"sp",	"south preceding"},
+	{"spectrum",	"spectrum"},
+	{"spindle",	"spindle"},
+	{"spir",	"spiral"},
+	{"spiral",	"spiral"},
+	{"st 9...",	"stars of mag. 9 and fainter"},
+	{"st 9...13",	"stars of mag. 9 to 13"},
+	{"st",	"stars"},
+	{"stell",	"stellar, pointlike"},
+	{"stellar",	"stellar"},
+	{"straight",	"straight"},
+	{"streak",	"streak"},
+	{"strongly",	"strongly"},
+	{"surrounded",	"surrounded"},
+	{"surrounds",	"surrounds"},
+	{"susp",	"suspected"},
+	{"suspected",	"suspected"},
+	{"tau",	"τ"},
+	{"theta",	"θ"},
+	{"trap",	"trapezium"},
+	{"trapez",	"trapezium"},
+	{"trapezium",	"trapezium"},
+	{"triN",	"trinuclear"},
+	{"v",	"very"},
+	{"var",	"variable"},
+	{"variable",	"variable"},
+	{"verification",	"verification"},
+	{"verified",	"verified"},
+	{"very",	"very"},
+	{"vl",	"very little"},
+	{"vm",	"very much"},
+	{"vs",	"very suddenly"},
+	{"vv",	"very very"},
+	{"zeta",	"ζ"},
+	{0,	0},
 };
 
 /*&
-	"ST9",	"stars from the 9th magnitude downward",
-	"ST9...13",	"stars from 9th to 13th magnitude",
-	"()",	"items questioned by Dreyer enclosed in parentheses",
+	{"ST9",	"stars from the 9th magnitude downward"},
+	{"ST9...13",	"stars from 9th to 13th magnitude"},
+	{"()",	"items questioned by Dreyer enclosed in parentheses"},
 	*10	star of 10th mag
-	"*",	"a star (or stars)",
-	"**",	"double star",
-	"***",	"triple star",
+	{"*",	"a star (or stars)"},
+	{"**",	"double star"},
+	{"***",	"triple star"},
 */

+ 1 - 1
sys/src/cmd/scat/dssread.c

@@ -103,7 +103,7 @@ dodecode(Biobuf *infile, Pix  *a, int nx, int ny, uint8_t *nbitplanes)
 	mask = 0;
 	bits = 0;;
 	for(; a<aend; a++) {
-		if(px = *a) {
+		if((px = *a)) {
 			if(mask == 0) {
 				mask = 0x80;
 				bits = Bgetc(infile);

+ 57 - 57
sys/src/cmd/scat/header.c

@@ -20,65 +20,65 @@ struct
 	char	offset;
 } Hproto[] =
 {
-	"ppo1",		Pppo1,
-	"ppo2",		Pppo2,
-	"ppo3",		Pppo3,
-	"ppo4",		Pppo4,
-	"ppo5",		Pppo5,
-	"ppo6",		Pppo6,
+	{"ppo1",		Pppo1},
+	{"ppo2",		Pppo2},
+	{"ppo3",		Pppo3},
+	{"ppo4",		Pppo4},
+	{"ppo5",		Pppo5},
+	{"ppo6",		Pppo6},
 
-	"amdx1",	Pamdx1,
-	"amdx2",	Pamdx2,
-	"amdx3",	Pamdx3,
-	"amdx4",	Pamdx4,
-	"amdx5",	Pamdx5,
-	"amdx6",	Pamdx6,
-	"amdx7",	Pamdx7,
-	"amdx8",	Pamdx8,
-	"amdx9",	Pamdx9,
-	"amdx10",	Pamdx10,
-	"amdx11",	Pamdx11,
-	"amdx12",	Pamdx12,
-	"amdx13",	Pamdx13,
-	"amdx14",	Pamdx14,
-	"amdx15",	Pamdx15,
-	"amdx16",	Pamdx16,
-	"amdx17",	Pamdx17,
-	"amdx18",	Pamdx18,
-	"amdx19",	Pamdx19,
-	"amdx20",	Pamdx20,
+	{"amdx1",	Pamdx1},
+	{"amdx2",	Pamdx2},
+	{"amdx3",	Pamdx3},
+	{"amdx4",	Pamdx4},
+	{"amdx5",	Pamdx5},
+	{"amdx6",	Pamdx6},
+	{"amdx7",	Pamdx7},
+	{"amdx8",	Pamdx8},
+	{"amdx9",	Pamdx9},
+	{"amdx10",	Pamdx10},
+	{"amdx11",	Pamdx11},
+	{"amdx12",	Pamdx12},
+	{"amdx13",	Pamdx13},
+	{"amdx14",	Pamdx14},
+	{"amdx15",	Pamdx15},
+	{"amdx16",	Pamdx16},
+	{"amdx17",	Pamdx17},
+	{"amdx18",	Pamdx18},
+	{"amdx19",	Pamdx19},
+	{"amdx20",	Pamdx20},
 
-	"amdy1",	Pamdy1,
-	"amdy2",	Pamdy2,
-	"amdy3",	Pamdy3,
-	"amdy4",	Pamdy4,
-	"amdy5",	Pamdy5,
-	"amdy6",	Pamdy6,
-	"amdy7",	Pamdy7,
-	"amdy8",	Pamdy8,
-	"amdy9",	Pamdy9,
-	"amdy10",	Pamdy10,
-	"amdy11",	Pamdy11,
-	"amdy12",	Pamdy12,
-	"amdy13",	Pamdy13,
-	"amdy14",	Pamdy14,
-	"amdy15",	Pamdy15,
-	"amdy16",	Pamdy16,
-	"amdy17",	Pamdy17,
-	"amdy18",	Pamdy18,
-	"amdy19",	Pamdy19,
-	"amdy20",	Pamdy20,
+	{"amdy1",	Pamdy1},
+	{"amdy2",	Pamdy2},
+	{"amdy3",	Pamdy3},
+	{"amdy4",	Pamdy4},
+	{"amdy5",	Pamdy5},
+	{"amdy6",	Pamdy6},
+	{"amdy7",	Pamdy7},
+	{"amdy8",	Pamdy8},
+	{"amdy9",	Pamdy9},
+	{"amdy10",	Pamdy10},
+	{"amdy11",	Pamdy11},
+	{"amdy12",	Pamdy12},
+	{"amdy13",	Pamdy13},
+	{"amdy14",	Pamdy14},
+	{"amdy15",	Pamdy15},
+	{"amdy16",	Pamdy16},
+	{"amdy17",	Pamdy17},
+	{"amdy18",	Pamdy18},
+	{"amdy19",	Pamdy19},
+	{"amdy20",	Pamdy20},
 
-	"pltscale",	Ppltscale,
-	"xpixelsz",	Pxpixelsz,
-	"ypixelsz",	Pypixelsz,
+	{"pltscale",	Ppltscale},
+	{"xpixelsz",	Pxpixelsz},
+	{"ypixelsz",	Pypixelsz},
 
-	"pltrah",	Ppltrah,
-	"pltram",	Ppltram,
-	"pltras",	Ppltras,
-	"pltdecd",	Ppltdecd,
-	"pltdecm",	Ppltdecm,
-	"pltdecs",	Ppltdecs,
+	{"pltrah",	Ppltrah},
+	{"pltram",	Ppltram},
+	{"pltras",	Ppltras},
+	{"pltdecd",	Ppltdecd},
+	{"pltdecm",	Ppltdecm},
+	{"pltdecs",	Ppltdecs},
 
 };
 
@@ -150,7 +150,7 @@ getheader(char *rgn)
 			if(j >= nelem(Hproto))
 				j = 0;
 			if(strcmp(name, Hproto[j].name) == 0) {
-				hd.param[Hproto[j].offset] = atof(value);
+				hd.param[(uintptr_t)Hproto[j].offset] = atof(value);
 				break;
 			}
 		}
@@ -222,7 +222,7 @@ getplates(void)
 			memmove(p->rgn, rec+0, 5);
 			if(p->rgn[4] == ' ')
 				p->rgn[4] = 0;
-			for(i=0; c=p->rgn[i]; i++)
+			for(i=0; (c=p->rgn[i]); i++)
 				if(c >= 'A' && c <= 'Z')
 					p->rgn[i] += 'a'-'A';
 			p->ra = RAD(atof(rec+12)*15 +

+ 0 - 25
sys/src/cmd/scat/mkfile

@@ -1,25 +0,0 @@
-</$objtype/mkfile
-
-TARG=scat
-OFILES=scat.$O\
-	bitinput.$O\
-	desc.$O\
-	display.$O\
-	dssread.$O\
-	header.$O\
-	hinv.$O\
-	image.$O\
-	patch.$O\
-	plot.$O\
-	posn.$O\
-	prose.$O\
-	qtree.$O\
-	util.$O\
-
-HFILES=sky.h
-CFLAGS=$CFLAGS -I/sys/src/cmd/map
-
-BIN=/$objtype/bin
-</sys/src/cmd/mkone
-
-scat.$O:	strings.c

+ 6 - 17
sys/src/cmd/scat/plot.c

@@ -56,26 +56,17 @@ double	mapscale;
 double	maps;
 int (*projection)(struct place*, double*, double*);
 
-char *fontname = "/lib/font/bit/lucida/unicode.6.font";
-
-/* types Coord and Loc correspond to types in map(3) thus:
+/* type Coord correspond to types in map(3) thus:
    Coord == struct coord;
-   Loc == struct place, except longitudes are measured
-     positive east for Loc and west for struct place
 */
 
 typedef struct Xyz Xyz;
 typedef struct coord Coord;
-typedef struct Loc Loc;
 
 struct Xyz{
 	double x,y,z;
 };
 
-struct Loc{
-	Coord nlat, elon;
-};
-
 Xyz north = { 0, 0, 1 };
 
 int
@@ -109,9 +100,7 @@ plotopen(void)
 	neptunecolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x77FF77FF);
 	plutocolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0x7777FFFF);
 	cometcolor = allocimage(display, Rect(0, 0, 1, 1), RGBA32, 1, 0xAAAAFFFF);
-	font = openfont(display, fontname);
-	if(font == nil)
-		fprint(2, "warning: no font %s: %r\n", fontname);
+	font = opendefaultfont(display);
 	return 1;
 }
 
@@ -230,7 +219,7 @@ rot(struct place center, struct place zenith)
 }
 
 int (*
-heavens(double zlatdeg, double zlondeg, double clatdeg, double clondeg))(Loc*, double*, double*)
+heavens(double zlatdeg, double zlondeg, double clatdeg, double clondeg))(struct place*, double*, double*)
 {
 	struct place center;
 	struct place zenith;
@@ -618,7 +607,7 @@ plot(char *flags)
 	dy = 512;
 	zenithup = 0;
 	for(;;){
-		if(t = alpha(flags, "nogrid")){
+		if((t = alpha(flags, "nogrid"))){
 			nogrid = 1;
 			flags = t;
 			continue;
@@ -638,7 +627,7 @@ plot(char *flags)
 			flags = t;
 			continue;
 		}
-		if(t = alpha(flags, "dx")){
+		if((t = alpha(flags, "dx"))){
 			dx = strtol(t, &t, 0);
 			if(dx < 100){
 				fprint(2, "dx %d too small (min 100) in plot\n", dx);
@@ -647,7 +636,7 @@ plot(char *flags)
 			flags = skipbl(t);
 			continue;
 		}
-		if(t = alpha(flags, "dy")){
+		if((t = alpha(flags, "dy"))){
 			dy = strtol(t, &t, 0);
 			if(dy < 100){
 				fprint(2, "dy %d too small (min 100) in plot\n", dy);

+ 1 - 1
sys/src/cmd/scat/prose.c

@@ -60,7 +60,7 @@ prose(char *s, char *desc[][2], int16_t index[])
 			*p++ = *s++;
 			continue;	/* below will copy the number */
 		}
-		if((i=index[*s]) == -1){
+		if((i=index[(uintptr_t)*s]) == -1){
 	Dup:
 			switch(*s){
 			default:

+ 43 - 42
sys/src/cmd/scat/scat.c

@@ -13,7 +13,7 @@
 #include <draw.h>
 #include <event.h>
 #include "sky.h"
-#include "strings.c"
+#include "strings.C"
 
 enum
 {
@@ -63,6 +63,7 @@ int32_t	noreca;
 Biobuf	bin;
 Biobuf	bout;
 
+int
 main(int argc, char *argv[])
 {
 	char *line;
@@ -72,7 +73,7 @@ main(int argc, char *argv[])
 	if(argc != 1)
 		dir = argv[1];
 	astro("", 1);
-	while(line = Brdline(&bin, '\n')){
+	while((line = Brdline(&bin, '\n'))){
 		line[Blinelen(&bin)-1] = 0;
 		lookup(line, 1);
 		Bflush(&bout);
@@ -595,28 +596,28 @@ cull(char *s, int keep, int dobbox)
 			s = skipbl(t);
 			continue;
 		}
-		if(t = text(s, "m")){
+		if((t = text(s, "m"))	){
  			dom = 1;
 			s = t;
 			continue;
 		}
-		if(t = text(s, "sao")){
+		if((t = text(s, "sao"))){
 			dosao = 1;
 			s = t;
 			continue;
 		}
-		if(t = text(s, "ngc")){
+		if((t = text(s, "ngc"))){
 			dongc = 1;
 			s = t;
 			continue;
 		}
-		if(t = text(s, "abell")){
+		if((t = text(s, "abell"))){
 			doabell = 1;
 			s = t;
 			continue;
 		}
 		for(i=0; names[i].name; i++)
-			if(t = alpha(s, names[i].name)){
+			if((t = alpha(s, names[i].name))){
 				if(nobj > 100){
 					fprint(2, "too many object types\n");
 					return 0;
@@ -675,7 +676,7 @@ cull(char *s, int keep, int dobbox)
 int
 compar(const void *va, const void *vb)
 {
-	Record *a=va, *b=vb;
+	Record const *a=va, *b=vb;
 
 	if(a->type == b->type)
 		return a->index - b->index;
@@ -1022,7 +1023,7 @@ lookup(char *s, int doreset)
 	if(*s == 0)
 		goto Print;
 
-	if(t = alpha(s, "flat")){
+	if((t = alpha(s, "flat"))){
 		if(*t){
 			fprint(2, "flat takes no arguments\n");
 			return;
@@ -1035,7 +1036,7 @@ lookup(char *s, int doreset)
 		goto Print;
 	}
 
-	if(t = alpha(s, "print")){
+	if((t = alpha(s, "print"))){
 		if(*t){
 			fprint(2, "print takes no arguments\n");
 			return;
@@ -1045,12 +1046,12 @@ lookup(char *s, int doreset)
 		return;
 	}
 
-	if(t = alpha(s, "add")){
+	if((t = alpha(s, "add"))){
 		lookup(t, 0);
 		return;
 	}
 
-	if(t = alpha(s, "sao")){
+	if((t = alpha(s, "sao"))){
 		n = strtoul(t, &u, 10);
 		if(n<=0 || n>NSAO)
 			goto NotFound;
@@ -1066,7 +1067,7 @@ lookup(char *s, int doreset)
 		goto Print;
 	}
 
-	if(t = alpha(s, "ngc")){
+	if((t = alpha(s, "ngc"))){
 		n = strtoul(t, &u, 10);
 		if(n<=0 || n>NNGC)
 			goto NotFound;
@@ -1082,7 +1083,7 @@ lookup(char *s, int doreset)
 		goto Print;
 	}
 
-	if(t = alpha(s, "ic")){
+	if((t = alpha(s, "ic"))){
 		n = strtoul(t, &u, 10);
 		if(n<=0 || n>NIC)
 			goto NotFound;
@@ -1098,7 +1099,7 @@ lookup(char *s, int doreset)
 		goto Print;
 	}
 
-	if(t = alpha(s, "abell")){
+	if((t = alpha(s, "abell"))){
 		n = strtoul(t, &u, 10);
 		if(n<=0 || n>NAbell)
 			goto NotFound;
@@ -1109,7 +1110,7 @@ lookup(char *s, int doreset)
 		goto Print;
 	}
 
-	if(t = alpha(s, "m")){
+	if((t = alpha(s, "m"))){
 		n = strtoul(t, &u, 10);
 		if(n<=0 || n>NM)
 			goto NotFound;
@@ -1130,7 +1131,7 @@ lookup(char *s, int doreset)
 	}
 
 	for(i=1; i<=Ncon; i++)
-		if(t = alpha(s, constel[i])){
+		if((t = alpha(s, constel[i]))){
 			if(*t){
 				fprint(2, "syntax error in constellation\n");
 				return;
@@ -1149,7 +1150,7 @@ lookup(char *s, int doreset)
 			goto Print;
 		}
 
-	if(t = alpha(s, "expand")){
+	if((t = alpha(s, "expand"))){
 		n = 0;
 		if(*t){
 			if(*t<'0' && '9'<*t){
@@ -1166,7 +1167,7 @@ lookup(char *s, int doreset)
 		goto Print;
 	}
 
-	if(t = alpha(s, "plot")){
+	if((t = alpha(s, "plot"))){
 		if(nrec == 0){
 			Bprint(&bout, "empty\n");
 			return;
@@ -1175,17 +1176,17 @@ lookup(char *s, int doreset)
 		return;
 	}
 
-	if(t = alpha(s, "astro")){
+	if((t = alpha(s, "astro"))){
 		astro(t, 0);
 		return;
 	}
 
-	if(t = alpha(s, "plate")){
+	if((t = alpha(s, "plate"))){
 		pplate(t);
 		return;
 	}
 
-	if(t = alpha(s, "gamma")){
+	if((t = alpha(s, "gamma"))){
 		while(*t==' ')
 			t++;
 		u = t;
@@ -1196,20 +1197,20 @@ lookup(char *s, int doreset)
 		return;
 	}
 
-	if(t = alpha(s, "keep")){
+	if((t = alpha(s, "keep"))){
 		if(!cull(t, 1, 0))
 			return;
 		goto Print;
 	}
 
-	if(t = alpha(s, "drop")){
+	if((t = alpha(s, "drop"))){
 		if(!cull(t, 0, 0))
 			return;
 		goto Print;
 	}
 
 	for(i=0; planet[i].name[0]; i++){
-		if(t = alpha(s, planet[i].name)){
+		if((t = alpha(s, planet[i].name))){
 			if(doreset)
 				reset();
 			loadplanet(i, nil);
@@ -1218,7 +1219,7 @@ lookup(char *s, int doreset)
 	}
 
 	for(i=0; names[i].name; i++){
-		if(t = alpha(s, names[i].name)){
+		if((t = alpha(s, names[i].name))){
 			if(*t){
 				fprint(2, "syntax error in type\n");
 				return;
@@ -1329,21 +1330,21 @@ lookup(char *s, int doreset)
 
 char *ngctypes[] =
 {
-[Galaxy] 		"Gx",
-[PlanetaryN]	"Pl",
-[OpenCl]		"OC",
-[GlobularCl]	"Gb",
-[DiffuseN]		"Nb",
-[NebularCl]	"C+N",
-[Asterism]		"Ast",
-[Knot]		"Kt",
-[Triple]		"***",
-[Double]		"D*",
-[Single]		"*",
-[Uncertain]	"?",
-[Nonexistent]	"-",
-[Unknown]	" ",
-[PlateDefect]	"PD",
+	[Galaxy] 		= "Gx",
+	[PlanetaryN]	= "Pl",
+	[OpenCl]		= "OC",
+	[GlobularCl]	= "Gb",
+	[DiffuseN]		= "Nb",
+	[NebularCl]	= "C+N",
+	[Asterism]		= "Ast",
+	[Knot]		= "Kt",
+	[Triple]		= "***",
+	[Double]		= "D*",
+	[Single]		= "*",
+	[Uncertain]	= "?",
+	[Nonexistent]	= "-",
+	[Unknown]	= " ",
+	[PlateDefect]	= "PD",
 };
 
 char*
@@ -1504,7 +1505,7 @@ nameof(Record *r)
 				i += snprint(buf+i, sizeof buf-i, "%d", s->name[1]);
 		}else
 			i = snprint(buf, sizeof buf, " %d", s->name[0]);
-		snprint(buf+i, sizeof buf-i, " %s", constel[s->name[2]]);
+		snprint(buf+i, sizeof buf-i, " %s", constel[(uintptr_t)s->name[2]]);
 		break;
 	case NGC:
 		n = &r->ngc;

+ 26 - 26
sys/src/cmd/scat/sky.h

@@ -13,7 +13,7 @@
  *		of prior implementations.
  *
  *	Keys:
- *		32 bits long. High 26 bits are encoded as described below.
+ *		32 bits int32_t. High 26 bits are encoded as described below.
  *		Low 6 bits are types:
  *
  *		Patch is ~ one square degree of sky.  It points to an otherwise
@@ -144,9 +144,9 @@ enum
 #define	NPlanet			20
 
 typedef float	Angle;	/* in radians */
-typedef long	DAngle;	/* on disk: in units of milliarcsec */
-typedef short	Mag;	/* multiplied by 10 */
-typedef long	Key;	/* known to be 4 bytes, unfortunately */
+typedef int32_t	DAngle;	/* on disk: in units of milliarcsec */
+typedef int16_t	Mag;	/* multiplied by 10 */
+typedef int32_t	Key;	/* known to be 4 bytes, unfortunately */
 
 /*
  * All integers are stored in little-endian order.
@@ -158,7 +158,7 @@ struct NGCrec{
 	DAngle	dummy1;	/* compatibility with old RNGC version */
 	DAngle	diam;
 	Mag	mag;
-	short	ngc;	/* if >NNGC, IC number is ngc-NNGC */
+	int16_t	ngc;	/* if >NNGC, IC number is ngc-NNGC */
 	char	diamlim;
 	char	type;
 	char	magtype;
@@ -173,10 +173,10 @@ struct Abellrec{
 	DAngle	glat;
 	DAngle	glong;
 	Mag	mag10;	/* mag of 10th brightest cluster member; in same place as ngc.mag*/
-	short	abell;
+	int16_t	abell;
 	DAngle	rad;
-	short	pop;
-	short	dist;
+	int16_t	pop;
+	int16_t	dist;
 	char	distgrp;
 	char	richgrp;
 	char	flag;
@@ -212,22 +212,22 @@ struct SAOrec{
 	char	compid[2];
 	char	hdcode;
 	char	pad1;
-	long	hd;		/* HD catalog number */
+	int32_t	hd;		/* HD catalog number */
 	char	name[3];	/* name[0]=alpha name[1]=2 name[3]=ori */
 	char	nname;		/* number of prose names */
 	/* 36 bytes to here */
 };
 
 typedef struct Mindexrec Mindexrec;
-struct Mindexrec{	/* code knows the bit patterns in here; this is a long */
+struct Mindexrec{	/* code knows the bit patterns in here; this is a int32_t */
 	char	m;		/* M number */
 	char	dummy;
-	short	ngc;
+	int16_t	ngc;
 };
 
 typedef struct Bayerec Bayerec;
 struct Bayerec{
-	long	sao;
+	int32_t	sao;
 	char	name[3];
 	char	pad;
 };
@@ -243,22 +243,22 @@ struct Namedrec{
 
 typedef struct Namerec Namerec;
 struct Namerec{
-	long	sao;
-	long	ngc;
-	long	abell;
+	int32_t	sao;
+	int32_t	ngc;
+	int32_t	abell;
 	char	name[36];	/* null terminated */
 };
 
 typedef struct Patchrec Patchrec;
 struct Patchrec{
 	int	nkey;
-	long	key[60];
+	int32_t	key[60];
 };
 
 typedef struct Record Record;
 struct Record{
 	Type	type;
-	long	index;
+	int32_t	index;
 	union{
 		SAOrec	sao;
 		NGCrec	ngc;
@@ -296,7 +296,7 @@ struct	Header
 	float	xi;
 	float	eta;
 };
-typedef	long	Pix;
+typedef	int32_t	Pix;
 
 typedef struct	Img Img;
 struct	Img
@@ -336,7 +336,7 @@ struct Picture
 	int	maxx;
 	int	maxy;
 	char	name[16];
-	uchar	*data;
+	uint8_t	*data;
 };
 
 typedef struct Image Image;
@@ -347,7 +347,7 @@ extern	char	*progname;
 extern	char	*desctab[][2];
 extern	Name	names[];
 extern	Record	*rec;
-extern	long		nrec;
+extern	int32_t		nrec;
 extern	Planetrec	*planet;
 /* for bbox: */
 extern	int		folded;
@@ -371,9 +371,9 @@ extern void prrec(Record*);
 extern int equal(char*, char*);
 extern int parsename(char*);
 extern void radec(int, int*, int*, int*);
-extern int btag(short);
-extern long patcha(Angle, Angle);
-extern long patch(int, int, int);
+extern int btag(int16_t);
+extern int32_t patcha(Angle, Angle);
+extern int32_t patch(int, int, int);
 extern char*hms(Angle);
 extern char*dms(Angle);
 extern char*ms(Angle);
@@ -381,9 +381,9 @@ extern char*hm(Angle);
 extern char*dm(Angle);
 extern char*deg(Angle);
 extern char*hm5(Angle);
-extern long dangle(Angle);
+extern int32_t dangle(Angle);
 extern Angle angle(DAngle);
-extern void prdesc(char*, char*(*)[2], short*);
+extern void prdesc(char*, char*(*)[2], int16_t*);
 extern double	xsqrt(double);
 extern Angle	dist(Angle, Angle, Angle, Angle);
 extern Header*	getheader(char*);
@@ -413,7 +413,7 @@ extern void	astro(char*, int);
 extern char*	alpha(char*, char*);
 extern char*	skipbl(char*);
 extern void	flatten(void);
-extern int		bbox(long, long, int);
+extern int		bbox(int32_t, int32_t, int);
 extern int		inbbox(DAngle, DAngle);
 extern char*	nameof(Record*);
 

+ 27 - 27
sys/src/cmd/scat/strings.c → sys/src/cmd/scat/strings.C

@@ -31,31 +31,31 @@ char *constel[]={ 0,	/* 1-indexed */
 	"tri", "tuc", "uma", "umi", "vel", "vir", "vol", "vul",
 };
 Name names[]={
-	"gx",	Galaxy,
-	"pl",	PlanetaryN,
-	"oc",	OpenCl,
-	"gb",	GlobularCl,
-	"nb",	DiffuseN,
-	"c+n",NebularCl,
-	"ast",	Asterism,
-	"kt",	Knot,
-	"***",	Triple,
-	"d*",	Double,
-	"*",	Single,
-	"pd",	PlateDefect,
-	"galaxy",	Galaxy,
-	"planetary",	PlanetaryN,
-	"opencluster",	OpenCl,
-	"globularcluster",	GlobularCl,
-	"nebula",	DiffuseN,
-	"nebularcluster",NebularCl,
-	"asterism",	Asterism,
-	"knot",	Knot,
-	"triple",	Triple,
-	"double",	Double,
-	"single",	Single,
-	"nonexistent",	Nonexistent,
-	"unknown",	Unknown,
-	"platedefect",	PlateDefect,
-	0,		0,
+	{"gx",	Galaxy},
+	{"pl",	PlanetaryN},
+	{"oc",	OpenCl},
+	{"gb",	GlobularCl},
+	{"nb",	DiffuseN},
+	{"c+n",	NebularCl},
+	{"ast",	Asterism},
+	{"kt",	Knot},
+	{"***",	Triple},
+	{"d*",	Double},
+	{"*",	Single},
+	{"pd",	PlateDefect},
+	{"galaxy",	Galaxy},
+	{"planetary",	PlanetaryN},
+	{"opencluster",	OpenCl},
+	{"globularcluster",	GlobularCl},
+	{"nebula",	DiffuseN},
+	{"nebularcluster",	NebularCl},
+	{"asterism",	Asterism},
+	{"knot",	Knot},
+	{"triple",	Triple},
+	{"double",	Double},
+	{"single",	Single},
+	{"nonexistent",	Nonexistent},
+	{"unknown",	Unknown},
+	{"platedefect",	PlateDefect},
+	{0,		0},
 };

+ 0 - 97
sys/src/cmd/webfs/buf.c

@@ -1,97 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ip.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include "dat.h"
-#include "fns.h"
-
-void
-initibuf(Ibuf *b, Ioproc *io, int fd)
-{
-	b->fd = fd;
-	b->io = io;
-	b->rp = b->wp = b->buf;
-}
-
-int
-readibuf(Ibuf *b, char *buf, int len)
-{
-	int n;
-
-	n = b->wp - b->rp;
-	if(n > 0){
-		if(n > len)
-			n = len;
-		memmove(buf, b->rp, n);
-		b->rp += n;
-		return n;
-	}
-	return ioreadn(b->io, b->fd, buf, len);
-}
-
-void
-unreadline(Ibuf *b, char *line)
-{
-	int i, n;
-
-	i = strlen(line);
-	n = b->wp - b->rp;
-	memmove(&b->buf[i+1], b->rp, n);
-	memmove(b->buf, line, i);
-	b->buf[i] = '\n';
-	b->rp = b->buf;
-	b->wp = b->rp+i+1+n;
-}
-
-int
-readline(Ibuf *b, char *buf, int len)
-{
-	int n;
-	char *p;
-
-	len--;
-
-	for(p = buf;;){
-		if(b->rp >= b->wp){
-			n = ioread(b->io, b->fd, b->wp, sizeof(b->buf)/2);
-			if(n < 0)
-				return -1;
-			if(n == 0)
-				break;
-			b->wp += n;
-		}
-		n = *b->rp++;
-		if(len > 0){
-			*p++ = n;
-			len--;
-		}
-		if(n == '\n')
-			break;
-	}
-
-	/* drop trailing white */
-	for(;;){
-		if(p <= buf)
-			break;
-		n = *(p-1);
-		if(n != ' ' && n != '\t' && n != '\r' && n != '\n')
-			break;
-		p--;
-	}
-
-	*p = 0;
-	return p-buf;
-}

+ 0 - 403
sys/src/cmd/webfs/client.c

@@ -1,403 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ip.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include "dat.h"
-#include "fns.h"
-
-int nclient;
-Client **client;
-
-static void clientthread(void*);
-int
-newclient(int plumbed)
-{
-	int i;
-	Client *c;
-
-	for(i=0; i<nclient; i++)
-		if(client[i]->ref==0)
-			return i;
-
-	c = emalloc(sizeof(Client));
-	c->plumbed = plumbed;
-	c->creq = chancreate(sizeof(Req*), 8);
-	threadcreate(clientthread, c, STACK);
-
-	c->io = ioproc();
-	c->num = nclient;
-	c->ctl = globalctl;
-	clonectl(&c->ctl);
-	if(nclient%16 == 0)
-		client = erealloc(client, (nclient+16)*sizeof(client[0]));
-	client[nclient++] = c;
-	return nclient-1;
-}
-
-void
-closeclient(Client *c)
-{
-	if(--c->ref == 0){
-		if(c->bodyopened){
-			if(c->url && c->url->close)
-				(*c->url->close)(c);
-			c->bodyopened = 0;
-		}
-		free(c->contenttype);
-		c->contenttype = nil;
-		free(c->postbody);
-		c->postbody = nil;
-		freeurl(c->url);
-		c->url = nil;
-		free(c->redirect);
-		c->redirect = nil;
-		free(c->authenticate);
-		c->authenticate = nil;
-		c->npostbody = 0;
-		c->havepostbody = 0;
-		c->bodyopened = 0;
-	}
-}
-
-void
-clonectl(Ctl *c)
-{
-	if(c->useragent)
-		c->useragent = estrdup(c->useragent);
-}
-
-void
-clientbodyopen(Client *c, Req *r)
-{
-	char e[ERRMAX], *next;
-	int i, nauth;
-	Url *u;
-
-	nauth = 0;
-	next = nil;
-	for(i=0; i<=c->ctl.redirectlimit; i++){
-		if(c->url == nil){
-			werrstr("nil url");
-			goto Error;
-		}
-		if(c->url->open == nil){
-			werrstr("unsupported url type");
-			goto Error;
-		}
-		if(fsdebug)
-			fprint(2, "try %s\n", c->url->url);
-		if(c->url->open(c, c->url) < 0){
-		Error:
-			if(next)
-				fprint(2, "next %s (but for error)\n", next);
-			free(next);
-			rerrstr(e, sizeof e);
-			c->iobusy = 0;
-			if(r != nil)
-				r->fid->omode = -1;
-			closeclient(c);	/* not opening */
-			if(r != nil)
-				respond(r, e);
-			return;
-		}
-		if (c->authenticate && nauth++ < 1)
-				continue;
-		if(!c->redirect)
-			break;
-		next = c->redirect;
-		c->redirect = nil;
-		if(i==c->ctl.redirectlimit){
-			werrstr("redirect limit reached");
-			goto Error;
-		}
-		if((u = parseurl(next, c->url)) == nil)
-			goto Error;
-		if(urldebug)
-			fprint(2, "parseurl %s got scheme %d\n", next, u->ischeme);
-		if(u->ischeme == USunknown){
-			werrstr("redirect with unknown URL scheme");
-			goto Error;
-		}
-		if(u->ischeme == UScurrent){
-			werrstr("redirect to URL relative to current document");
-			goto Error;
-		}
-		freeurl(c->url);
-		c->url = u;
-	}
-	free(next);
-	c->iobusy = 0;
-	if(r != nil)
-		respond(r, nil);
-}
-
-void
-plumburl(char *url, char *base)
-{
-	int i;
-	Client *c;
-	Url *ubase, *uurl;
-
-	ubase = nil;
-	if(base){
-		ubase = parseurl(base, nil);
-		if(ubase == nil)
-			return;
-	}
-	uurl = parseurl(url, ubase);
-	if(uurl == nil){
-		freeurl(ubase);
-		return;
-	}
-	i = newclient(1);
-	c = client[i];
-	c->ref++;
-	c->baseurl = ubase;
-	c->url = uurl;
-	sendp(c->creq, nil);
-}
-
-void
-clientbodyread(Client *c, Req *r)
-{
-	char e[ERRMAX];
-
-	if(c->url->read == nil){
-		respond(r, "unsupported url type");
-		return;
-	}
-	if(c->url->read(c, r) < 0){
-		rerrstr(e, sizeof e);
-		c->iobusy = 0;
-		respond(r, e);
-		return;
-	}
-	c->iobusy = 0;
-	respond(r, nil);
-}
-
-static void
-clientthread(void *a)
-{
-	Client *c;
-	Req *r;
-
-	c = a;
-	if(c->plumbed) {
-		recvp(c->creq);
-		if(c->url == nil){
-			fprint(2, "bad url got plumbed\n");
-			return;
-		}
-		clientbodyopen(c, nil);
-		replumb(c);
-	}
-	while((r = recvp(c->creq)) != nil){
-		if(fsdebug)
-			fprint(2, "clientthread %F\n", &r->ifcall);
-		switch(r->ifcall.type){
-		case Topen:
-			if(c->plumbed) {
-				c->plumbed = 0;
-				c->ref--;			/* from plumburl() */
-				respond(r, nil);
-			}
-			else
-				clientbodyopen(c, r);
-			break;
-		case Tread:
-			clientbodyread(c, r);
-			break;
-		case Tflush:
-			respond(r, nil);
-		}
-		if(fsdebug)
-			fprint(2, "clientthread finished req\n");
-	}
-}
-
-enum
-{
-	Bool,
-	Int,
-	String,
-	XUrl,
-	Fn,
-};
-
-typedef struct Ctab Ctab;
-struct Ctab {
-	char *name;
-	int type;
-	void *offset;
-};
-
-Ctab ctltab[] = {
-	"acceptcookies",	Bool,		(void*)offsetof(Ctl, acceptcookies),
-	"sendcookies",		Bool,		(void*)offsetof(Ctl, sendcookies),
-	"redirectlimit",		Int,		(void*)offsetof(Ctl, redirectlimit),
-	"useragent",		String,	(void*)offsetof(Ctl, useragent),
-};
-
-Ctab globaltab[] = {
-	"chatty9p",		Int,		&chatty9p,
-	"fsdebug",		Int,		&fsdebug,
-	"cookiedebug",		Int,		&cookiedebug,
-	"urldebug",		Int,		&urldebug,
-	"httpdebug",		Int,		&httpdebug,
-};
-
-Ctab clienttab[] = {
-	"baseurl",			XUrl,		(void*)offsetof(Client, baseurl),
-	"url",				XUrl,		(void*)offsetof(Client, url),
-};
-
-static Ctab*
-findcmd(char *cmd, Ctab *tab, int ntab)
-{
-	int i;
-
-	for(i=0; i<ntab; i++)
-		if(strcmp(tab[i].name, cmd) == 0)
-			return &tab[i];
-	return nil;
-}
-
-static void
-parseas(Req *r, char *arg, int type, void *a)
-{
-	Url *u;
-	char e[ERRMAX];
-
-	switch(type){
-	case Bool:
-		if(strcmp(arg, "on")==0 || strcmp(arg, "1")==0)
-			*(int*)a = 1;
-		else
-			*(int*)a = 0;
-		break;
-	case String:
-		free(*(char**)a);
-		*(char**)a = estrdup(arg);
-		break;
-	case XUrl:
-		u = parseurl(arg, nil);
-		if(u == nil){
-			snprint(e, sizeof e, "parseurl: %r");
-			respond(r, e);
-			return;
-		}
-		freeurl(*(Url**)a);
-		*(Url**)a = u;
-		break;
-	case Int:
-		if(strcmp(arg, "on")==0)
-			*(int*)a = 1;
-		else
-			*(int*)a = atoi(arg);
-		break;
-	}
-	respond(r, nil);
-}
-
-int
-ctlwrite(Req *r, Ctl *ctl, char *cmd, char *arg)
-{
-	void *a;
-	Ctab *t;
-
-	if((t = findcmd(cmd, ctltab, nelem(ctltab))) == nil)
-		return 0;
-	a = (void*)((uintptr)ctl+(uintptr)t->offset);
-	parseas(r, arg, t->type, a);
-	return 1;
-}
-
-int
-clientctlwrite(Req *r, Client *c, char *cmd, char *arg)
-{
-	void *a;
-	Ctab *t;
-
-	if((t = findcmd(cmd, clienttab, nelem(clienttab))) == nil)
-		return 0;
-	a = (void*)((uintptr)c+(uintptr)t->offset);
-	parseas(r, arg, t->type, a);
-	return 1;
-}
-
-int
-globalctlwrite(Req *r, char *cmd, char *arg)
-{
-	void *a;
-	Ctab *t;
-
-	if((t = findcmd(cmd, globaltab, nelem(globaltab))) == nil)
-		return 0;
-	a = t->offset;
-	parseas(r, arg, t->type, a);
-	return 1;
-}
-
-static void
-ctlfmt(Ctl *c, char *s)
-{
-	int i;
-	void *a;
-	char *t;
-
-	for(i=0; i<nelem(ctltab); i++){
-		a = (void*)((uintptr)c+(uintptr)ctltab[i].offset);
-		switch(ctltab[i].type){
-		case Bool:
-			s += sprint(s, "%s %s\n", ctltab[i].name, *(int*)a ? "on" : "off");
-			break;
-		case Int:
-			s += sprint(s, "%s %d\n", ctltab[i].name, *(int*)a);
-			break;
-		case String:
-			t = *(char**)a;
-			if(t != nil)
-				s += sprint(s, "%s %.*s%s\n", ctltab[i].name, utfnlen(t, 100), t, strlen(t)>100 ? "..." : "");
-			break;
-		}
-	}
-}
-
-void
-ctlread(Req *r, Client *c)
-{
-	char buf[1024];
-
-	sprint(buf, "%11d \n", c->num);
-	ctlfmt(&c->ctl, buf+strlen(buf));
-	readstr(r, buf);
-	respond(r, nil);
-}
-
-void
-globalctlread(Req *r)
-{
-	char buf[1024], *s;
-	int i;
-
-	s = buf;
-	for(i=0; i<nelem(globaltab); i++)
-		s += sprint(s, "%s %d\n", globaltab[i].name, *(int*)globaltab[i].offset);
-	ctlfmt(&globalctl, s);
-	readstr(r, buf);
-	respond(r, nil);
-}

+ 0 - 1182
sys/src/cmd/webfs/cookies.c

@@ -1,1182 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ndb.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-#include <ctype.h>
-#include "dat.h"
-#include "fns.h"
-
-int cookiedebug;
-
-typedef struct Cookie Cookie;
-typedef struct Jar Jar;
-
-struct Cookie
-{
-	/* external info */
-	char*	name;
-	char*	value;
-	char*	dom;		/* starts with . */
-	char*	path;
-	char*	version;
-	char*	comment;		/* optional, may be nil */
-
-	uint		expire;		/* time of expiration: ~0 means when webcookies dies */
-	int		secure;
-	int		explicitdom;	/* dom was explicitly set */
-	int		explicitpath;	/* path was explicitly set */
-	int		netscapestyle;
-
-	/* internal info */
-	int		deleted;
-	int		mark;
-	int		ondisk;
-};
-
-struct Jar
-{
-	Cookie	*c;
-	int		nc;
-	int		mc;
-
-	Qid		qid;
-	int		dirty;
-	char		*file;
-	char		*lockfile;
-};
-
-struct {
-	char *s;
-	int	offset;
-	int	ishttp;
-} stab[] = {
-	"domain",		offsetof(Cookie, dom),		1,
-	"path",		offsetof(Cookie, path),		1,
-	"name",		offsetof(Cookie, name),		0,
-	"value",		offsetof(Cookie, value),		0,
-	"comment",	offsetof(Cookie, comment),	1,
-	"version",		offsetof(Cookie, version),		1,
-};
-
-struct {
-	char *s;
-	int	offset;
-} itab[] = {
-	"expire",			offsetof(Cookie, expire),
-	"secure",			offsetof(Cookie, secure),
-	"explicitdomain",	offsetof(Cookie, explicitdom),
-	"explicitpath",		offsetof(Cookie, explicitpath),
-	"netscapestyle",	offsetof(Cookie, netscapestyle),
-};
-
-
-/* HTTP format */
-static int
-jarfmt(Fmt *fp)
-{
-	int i;
-	Jar *jar;
-
-	jar = va_arg(fp->args, Jar*);
-
-	if(jar == nil || jar->nc == 0)
-		return 0;
-
-	fmtstrcpy(fp, "Cookie: ");
-	if(jar->c[0].version)
-		fmtprint(fp, "$Version=%s; ", jar->c[0].version);
-	for(i=0; i<jar->nc; i++)
-		fmtprint(fp, "%s%s=%s", i ? "; ": "", jar->c[i].name, jar->c[i].value);
-	fmtstrcpy(fp, "\r\n");
-	return 0;
-}
-
-/* individual cookie */
-static int
-cookiefmt(Fmt *fp)
-{
-	int j, k, first;
-	char *t;
-	Cookie *c;
-
-	c = va_arg(fp->args, Cookie*);
-
-	first = 1;
-	for(j=0; j<nelem(stab); j++){
-		t = *(char**)((uintptr)c+stab[j].offset);
-		if(t == nil)
-			continue;
-		if(first)
-			first = 0;
-		else
-			fmtstrcpy(fp, " ");
-		fmtprint(fp, "%s=%q", stab[j].s, t);
-	}
-	for(j=0; j<nelem(itab); j++){
-		k = *(int*)((uintptr)c+itab[j].offset);
-		if(k == 0)
-			continue;
-		if(first)
-			first = 0;
-		else
-			fmtstrcpy(fp, " ");
-		fmtprint(fp, "%s=%u", itab[j].s, k);
-	}
-	return 0;
-}
-
-/*
- * sort cookies:
- *	- alpha by name
- *	- alpha by domain
- *	- longer paths first, then alpha by path (RFC2109 4.3.4)
- */
-static int
-cookiecmp(const Cookie *a, const Cookie *b)
-{
-	int i;
-
-	if((i = strcmp(a->name, b->name)) != 0)
-		return i;
-	if((i = cistrcmp(a->dom, b->dom)) != 0)
-		return i;
-	if((i = strlen(b->path) - strlen(a->path)) != 0)
-		return i;
-	if((i = strcmp(a->path, b->path)) != 0)
-		return i;
-	return 0;
-}
-
-static int
-exactcookiecmp(const Cookie *a, const Cookie *b)
-{
-	int i;
-
-	if((i = cookiecmp(a, b)) != 0)
-		return i;
-	if((i = strcmp(a->value, b->value)) != 0)
-		return i;
-	if(a->version || b->version){
-		if(!a->version)
-			return -1;
-		if(!b->version)
-			return 1;
-		if((i = strcmp(a->version, b->version)) != 0)
-			return i;
-	}
-	if(a->comment || b->comment){
-		if(!a->comment)
-			return -1;
-		if(!b->comment)
-			return 1;
-		if((i = strcmp(a->comment, b->comment)) != 0)
-			return i;
-	}
-	if((i = b->expire - a->expire) != 0)
-		return i;
-	if((i = b->secure - a->secure) != 0)
-		return i;
-	if((i = b->explicitdom - a->explicitdom) != 0)
-		return i;
-	if((i = b->explicitpath - a->explicitpath) != 0)
-		return i;
-	if((i = b->netscapestyle - a->netscapestyle) != 0)
-		return i;
-
-	return 0;
-}
-
-static void
-freecookie(Cookie *c)
-{
-	int i;
-
-	for(i=0; i<nelem(stab); i++)
-		free(*(char**)((uintptr)c+stab[i].offset));
-}
-
-static void
-copycookie(Cookie *c)
-{
-	int i;
-	char **ps;
-
-	for(i=0; i<nelem(stab); i++){
-		ps = (char**)((uintptr)c+stab[i].offset);
-		if(*ps)
-			*ps = estrdup9p(*ps);
-	}
-}
-
-static void
-delcookie(Jar *j, Cookie *c)
-{
-	int i;
-
-	j->dirty = 1;
-	i = c - j->c;
-	if(i < 0 || i >= j->nc)
-		abort();
-	c->deleted = 1;
-}
-
-static void
-addcookie(Jar *j, Cookie *c)
-{
-	int i;
-
-	if(!c->name || !c->value || !c->path || !c->dom){
-		fprint(2, "not adding incomplete cookie\n");
-		return;
-	}
-
-	if(cookiedebug)
-		fprint(2, "add %K\n", c);
-
-	for(i=0; i<j->nc; i++)
-		if(cookiecmp(&j->c[i], c) == 0){
-			if(cookiedebug)
-				fprint(2, "cookie %K matches %K\n", &j->c[i], c);
-			if(exactcookiecmp(&j->c[i], c) == 0){
-				if(cookiedebug)
-					fprint(2, "\texactly\n");
-				j->c[i].mark = 0;
-				return;
-			}
-			delcookie(j, &j->c[i]);
-		}
-
-	j->dirty = 1;
-	if(j->nc == j->mc){
-		j->mc += 16;
-		j->c = erealloc9p(j->c, j->mc*sizeof(Cookie));
-	}
-	j->c[j->nc] = *c;
-	copycookie(&j->c[j->nc]);
-	j->nc++;
-}
-
-static void
-purgejar(Jar *j)
-{
-	int i;
-
-	for(i=j->nc-1; i>=0; i--){
-		if(!j->c[i].deleted)
-			continue;
-		freecookie(&j->c[i]);
-		--j->nc;
-		j->c[i] = j->c[j->nc];
-	}
-}
-
-static void
-addtojar(Jar *jar, char *line, int ondisk)
-{
-	Cookie c;
-	int i, j, nf, *pint;
-	char *f[20], *attr, *val, **pstr;
-
-	memset(&c, 0, sizeof c);
-	c.expire = ~0;
-	c.ondisk = ondisk;
-	nf = tokenize(line, f, nelem(f));
-	for(i=0; i<nf; i++){
-		attr = f[i];
-		if((val = strchr(attr, '=')) != nil)
-			*val++ = '\0';
-		else
-			val = "";
-		/* string attributes */
-		for(j=0; j<nelem(stab); j++){
-			if(strcmp(stab[j].s, attr) == 0){
-				pstr = (char**)((uintptr)&c+stab[j].offset);
-				*pstr = val;
-			}
-		}
-		/* integer attributes */
-		for(j=0; j<nelem(itab); j++){
-			if(strcmp(itab[j].s, attr) == 0){
-				pint = (int*)((uintptr)&c+itab[j].offset);
-				if(val[0]=='\0')
-					*pint = 1;
-				else
-					*pint = strtoul(val, 0, 0);
-			}
-		}
-	}
-	if(c.name==nil || c.value==nil || c.dom==nil || c.path==nil){
-		if(cookiedebug)
-			fprint(2, "ignoring fractional cookie %K\n", &c);
-		return;
-	}
-	addcookie(jar, &c);
-}
-
-static Jar*
-newjar(void)
-{
-	Jar *jar;
-
-	jar = emalloc9p(sizeof(Jar));
-	return jar;
-}
-
-static int
-expirejar(Jar *jar, int exiting)
-{
-	int i, n;
-	uint now;
-
-	now = time(0);
-	n = 0;
-	for(i=0; i<jar->nc; i++){
-		if(jar->c[i].expire < now || (exiting && jar->c[i].expire==~0)){
-			delcookie(jar, &jar->c[i]);
-			n++;
-		}
-	}
-	return n;
-}
-
-static void
-dumpjar(Jar *jar, char *desc)
-{
-	int i;
-	Biobuf *b;
-	char *s;
-
-	print("%s\n", desc);
-	print("\tin memory:\n");
-
-	for(i=0; i<jar->nc; i++)
-		print("\t%K%s%s%s\n", &jar->c[i],
-			jar->c[i].ondisk ? " ondisk" : "",
-			jar->c[i].deleted ? " deleted" : "",
-			jar->c[i].mark ? " mark" : "");
-	print("\n\ton disk:\n");
-	if((b = Bopen(jar->file, OREAD)) == nil){
-		print("\tno file\n");
-	}else{
-		while((s = Brdstr(b, '\n', 1)) != nil){
-			print("\t%s\n", s);
-			free(s);
-		}
-		Bterm(b);
-	}
-	print("\n");
-}
-
-static int
-syncjar(Jar *jar)
-{
-	int i, fd;
-	char *line;
-	Dir *d;
-	Biobuf *b;
-	Qid q;
-
-	if(jar->file==nil)
-		return 0;
-
-	memset(&q, 0, sizeof q);
-	if((d = dirstat(jar->file)) != nil){
-		q = d->qid;
-		if(d->qid.path != jar->qid.path || d->qid.vers != jar->qid.vers)
-			jar->dirty = 1;
-		free(d);
-	}
-
-	if(jar->dirty == 0)
-		return 0;
-
-	fd = -1;
-	for(i=0; i<50; i++){
-		if((fd = create(jar->lockfile, OWRITE, DMEXCL|0666)) < 0){
-			sleep(100);
-			continue;
-		}
-		break;
-	}
-	if(fd < 0){
-		if(cookiedebug)
-			fprint(2, "open %s: %r", jar->lockfile);
-		werrstr("cannot acquire jar lock: %r");
-		return -1;
-	}
-
-	for(i=0; i<jar->nc; i++)	/* mark is cleared by addcookie */
-		jar->c[i].mark = jar->c[i].ondisk;
-
-	if((b = Bopen(jar->file, OREAD)) == nil){
-		if(cookiedebug)
-			fprint(2, "Bopen %s: %r", jar->file);
-		werrstr("cannot read cookie file %s: %r", jar->file);
-		close(fd);
-		return -1;
-	}
-	for(; (line = Brdstr(b, '\n', 1)) != nil; free(line)){
-		if(*line == '#')
-			continue;
-		addtojar(jar, line, 1);
-	}
-	Bterm(b);
-
-	for(i=0; i<jar->nc; i++)
-		if(jar->c[i].mark && jar->c[i].expire != ~0)
-			delcookie(jar, &jar->c[i]);
-
-	purgejar(jar);
-
-	b = Bopen(jar->file, OWRITE);
-	if(b == nil){
-		if(cookiedebug)
-			fprint(2, "Bopen write %s: %r", jar->file);
-		close(fd);
-		return -1;
-	}
-	Bprint(b, "# webcookies cookie jar\n");
-	Bprint(b, "# comments and non-standard fields will be lost\n");
-	for(i=0; i<jar->nc; i++){
-		if(jar->c[i].expire == ~0)
-			continue;
-		Bprint(b, "%K\n", &jar->c[i]);
-		jar->c[i].ondisk = 1;
-	}
-	Bterm(b);
-
-	jar->dirty = 0;
-	close(fd);
-	if((d = dirstat(jar->file)) != nil){
-		jar->qid = d->qid;
-		free(d);
-	}
-	return 0;
-}
-
-static Jar*
-readjar(char *file)
-{
-	char *lock, *p;
-	Jar *jar;
-
-	jar = newjar();
-	lock = emalloc9p(strlen(file)+10);
-	strcpy(lock, file);
-	if((p = strrchr(lock, '/')) != nil)
-		p++;
-	else
-		p = lock;
-	memmove(p+2, p, strlen(p)+1);
-	p[0] = 'L';
-	p[1] = '.';
-	jar->lockfile = lock;
-	jar->file = file;
-	jar->dirty = 1;
-
-	if(syncjar(jar) < 0){
-		free(jar->file);
-		free(jar->lockfile);
-		free(jar);
-		return nil;
-	}
-	return jar;
-}
-
-static void
-closejar(Jar *jar)
-{
-	int i;
-
-	if(jar == nil)
-		return;
-	expirejar(jar, 0);
-	if(syncjar(jar) < 0)
-		fprint(2, "warning: cannot rewrite cookie jar: %r\n");
-
-	for(i=0; i<jar->nc; i++)
-		freecookie(&jar->c[i]);
-
-	free(jar->file);
-	free(jar);
-}
-
-/*
- * Domain name matching is per RFC2109, section 2:
- *
- * Hosts names can be specified either as an IP address or a FQHN
- * string.  Sometimes we compare one host name with another.  Host A's
- * name domain-matches host B's if
- *
- * * both host names are IP addresses and their host name strings match
- *   exactly; or
- *
- * * both host names are FQDN strings and their host name strings match
- *   exactly; or
- *
- * * A is a FQDN string and has the form NB, where N is a non-empty name
- *   string, B has the form .B', and B' is a FQDN string.  (So, x.y.com
- *   domain-matches .y.com but not y.com.)
- *
- * Note that domain-match is not a commutative operation: a.b.c.com
- * domain-matches .c.com, but not the reverse.
- *
- * (This does not verify that IP addresses and FQDN's are well-formed.)
- */
-static int
-isdomainmatch(char *name, char *pattern)
-{
-	int lname, lpattern;
-
-	if(cistrcmp(name, pattern)==0)
-		return 1;
-
-	if(strcmp(ipattr(name), "dom")==0 && pattern[0]=='.'){
-		lname = strlen(name);
-		lpattern = strlen(pattern);
-		/* e.g., name: www.google.com && pattern: .google.com */
-		if(lname >= lpattern && cistrcmp(name+lname-lpattern, pattern)==0)
-			return 1;
-		/* e.g., name: google.com && pattern: .google.com */
-		if(lpattern > lname &&
-		    cistrcmp(pattern+lpattern-lname, name) == 0)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * RFC2109 4.3.4:
- *	- domain must match
- *	- path in cookie must be a prefix of request path
- *	- cookie must not have expired
- */
-static int
-iscookiematch(Cookie *c, char *dom, char *path, uint now)
-{
-	return isdomainmatch(dom, c->dom)
-		&& strncmp(c->path, path, strlen(c->path))==0
-		&& (c->expire == 0 || c->expire >= now);
-}
-
-/*
- * Produce a subjar of matching cookies.
- * Secure cookies are only included if secure is set.
- */
-static Jar*
-cookiesearch(Jar *jar, char *dom, char *path, int issecure)
-{
-	int i;
-	Jar *j;
-	uint now;
-
-	if(cookiedebug)
-		fprint(2, "cookiesearch %s %s %d\n", dom, path, issecure);
-	now = time(0);
-	j = newjar();
-	for(i=0; i<jar->nc; i++){
-		if(cookiedebug)
-			fprint(2, "\ttry %s %s %d %s\n", jar->c[i].dom,
-				jar->c[i].path, jar->c[i].secure,
-				jar->c[i].name);
-		if((issecure || !jar->c[i].secure) &&
-		    iscookiematch(&jar->c[i], dom, path, now)){
-			if(cookiedebug)
-				fprint(2, "\tmatched\n");
-			addcookie(j, &jar->c[i]);
-		}
-	}
-	if(j->nc == 0){
-		closejar(j);
-		werrstr("no cookies found");
-		return nil;
-	}
-	qsort(j->c, j->nc, sizeof(j->c[0]), cookiecmp);
-	return j;
-}
-
-/*
- * RFC2109 4.3.2 security checks
- */
-static char*
-isbadcookie(Cookie *c, char *dom, char *path)
-{
-	int lcdom, ldom;
-
-	if(strncmp(c->path, path, strlen(c->path)) != 0)
-		return "cookie path is not a prefix of the request path";
-
-	/*
-	 * fgb says omitting this test is necessary to get some sites to work,
-	 * but it seems dubious.
-	 */
-	if(c->explicitdom && c->dom[0] != '.')
-		return "cookie domain doesn't start with dot";
-
-	lcdom = strlen(c->dom);
-	if(memchr(c->dom+1, '.', lcdom-1-1) == nil)
-		return "cookie domain doesn't have embedded dots";
-
-	if(!isdomainmatch(dom, c->dom))
-		return "request host does not match cookie domain";
-
-	ldom = strlen(dom);
-	if(strcmp(ipattr(dom), "dom")==0 && lcdom > ldom &&
-	    memchr(dom, '.', lcdom - ldom) != nil)
-		return "request host contains dots before cookie domain";
-
-	return 0;
-}
-
-/*
- * Sunday, 25-Jan-2002 12:24:36 GMT
- * Sunday, 25 Jan 2002 12:24:36 GMT
- * Sun, 25 Jan 02 12:24:36 GMT
- */
-static int
-isleap(int year)
-{
-	return year%4==0 && (year%100!=0 || year%400==0);
-}
-
-static uint
-strtotime(char *s)
-{
-	char *os;
-	int i;
-	Tm tm;
-
-	static int mday[2][12] = {
-		31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
-		31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
-	};
-	static char *wday[] = {
-		"Sunday", "Monday", "Tuesday", "Wednesday",
-		"Thursday", "Friday", "Saturday",
-	};
-	static char *mon[] = {
-		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
-		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-	};
-
-	os = s;
-	/* Sunday, */
-	for(i=0; i<nelem(wday); i++){
-		if(cistrncmp(s, wday[i], strlen(wday[i])) == 0){
-			s += strlen(wday[i]);
-			break;
-		}
-		if(cistrncmp(s, wday[i], 3) == 0){
-			s += 3;
-			break;
-		}
-	}
-	if(i==nelem(wday)){
-		if(cookiedebug)
-			fprint(2, "bad wday (%s)\n", os);
-		return -1;
-	}
-	if(*s++ != ',' || *s++ != ' '){
-		if(cookiedebug)
-			fprint(2, "bad wday separator (%s)\n", os);
-		return -1;
-	}
-
-	/* 25- */
-	if(!isdigit(s[0]) || !isdigit(s[1]) || (s[2]!='-' && s[2]!=' ')){
-		if(cookiedebug)
-			fprint(2, "bad day of month (%s)\n", os);
-		return -1;
-	}
-	tm.mday = strtol(s, 0, 10);
-	s += 3;
-
-	/* Jan- */
-	for(i=0; i<nelem(mon); i++)
-		if(cistrncmp(s, mon[i], 3) == 0){
-			tm.mon = i;
-			s += 3;
-			break;
-		}
-	if(i==nelem(mon)){
-		if(cookiedebug)
-			fprint(2, "bad month (%s)\n", os);
-		return -1;
-	}
-	if(s[0] != '-' && s[0] != ' '){
-		if(cookiedebug)
-			fprint(2, "bad month separator (%s)\n", os);
-		return -1;
-	}
-	s++;
-
-	/* 2002 */
-	if(!isdigit(s[0]) || !isdigit(s[1])){
-		if(cookiedebug)
-			fprint(2, "bad year (%s)\n", os);
-		return -1;
-	}
-	tm.year = strtol(s, 0, 10);
-	s += 2;
-	if(isdigit(s[0]) && isdigit(s[1]))
-		s += 2;
-	else{
-		if(tm.year <= 68)
-			tm.year += 2000;
-		else
-			tm.year += 1900;
-	}
-	if(tm.mday==0 || tm.mday > mday[isleap(tm.year)][tm.mon]){
-		if(cookiedebug)
-			fprint(2, "invalid day of month (%s)\n", os);
-		return -1;
-	}
-	tm.year -= 1900;
-	if(*s++ != ' '){
-		if(cookiedebug)
-			fprint(2, "bad year separator (%s)\n", os);
-		return -1;
-	}
-
-	if(!isdigit(s[0]) || !isdigit(s[1]) || s[2]!=':'
-	|| !isdigit(s[3]) || !isdigit(s[4]) || s[5]!=':'
-	|| !isdigit(s[6]) || !isdigit(s[7]) || s[8]!=' '){
-		if(cookiedebug)
-			fprint(2, "bad time (%s)\n", os);
-		return -1;
-	}
-
-	tm.hour = atoi(s);
-	tm.min = atoi(s+3);
-	tm.sec = atoi(s+6);
-	if(tm.hour >= 24 || tm.min >= 60 || tm.sec >= 60){
-		if(cookiedebug)
-			fprint(2, "invalid time (%s)\n", os);
-		return -1;
-	}
-	s += 9;
-
-	if(cistrcmp(s, "GMT") != 0){
-		if(cookiedebug)
-			fprint(2, "time zone not GMT (%s)\n", os);
-		return -1;
-	}
-	strcpy(tm.zone, "GMT");
-	tm.yday = 0;
-	return tm2sec(&tm);
-}
-
-/*
- * skip linear whitespace.  we're a bit more lenient than RFC2616 2.2.
- */
-static char*
-skipspace(char *s)
-{
-	while(*s=='\r' || *s=='\n' || *s==' ' || *s=='\t')
-		s++;
-	return s;
-}
-
-/*
- * Try to identify old netscape headers.
- * The old headers:
- *	- didn't allow spaces around the '='
- *	- used an 'Expires' attribute
- *	- had no 'Version' attribute
- *	- had no quotes
- *	- allowed whitespace in values
- *	- apparently separated attr/value pairs with ';' exclusively
- */
-static int
-isnetscape(char *hdr)
-{
-	char *s;
-
-	for(s=hdr; (s=strchr(s, '=')) != nil; s++){
-		if(isspace(s[1]) || (s > hdr && isspace(s[-1])))
-			return 0;
-		if(s[1]=='"')
-			return 0;
-	}
-	if(cistrstr(hdr, "version="))
-		return 0;
-	return 1;
-}
-
-/*
- * Parse HTTP response headers, adding cookies to jar.
- * Overwrites the headers.  May overwrite path.
- */
-static char* parsecookie(Cookie*, char*, char**, int, char*,
-			   char*);
-static int
-parsehttp(Jar *jar, char *hdr, char *dom, char *path)
-{
-	static char setcookie[] = "Set-Cookie:";
-	char *e, *p, *nextp;
-	Cookie c;
-	int isns, n;
-
-	isns = isnetscape(hdr);
-	n = 0;
-	for(p=hdr; p; p=nextp){
-		p = skipspace(p);
-		if(*p == '\0')
-			break;
-		nextp = strchr(p, '\n');
-		if(nextp != nil)
-			*nextp++ = '\0';
-		if(cistrncmp(p, setcookie, strlen(setcookie)) != 0)
-			continue;
-		if(cookiedebug)
-			fprint(2, "%s\n", p);
-		p = skipspace(p+strlen(setcookie));
-		for(; *p; p=skipspace(p)){
-			if((e = parsecookie(&c, p, &p, isns, dom, path)) != nil){
-				if(cookiedebug)
-					fprint(2, "parse cookie: %s\n", e);
-				break;
-			}
-			if((e = isbadcookie(&c, dom, path)) != nil){
-				if(cookiedebug)
-					fprint(2, "reject cookie; %s\n", e);
-				continue;
-			}
-			addcookie(jar, &c);
-			n++;
-		}
-	}
-	return n;
-}
-
-static char*
-skipquoted(char *s)
-{
-	/*
-	 * Sec 2.2 of RFC2616 defines a "quoted-string" as:
-	 *
-	 *  quoted-string  = ( <"> *(qdtext | quoted-pair ) <"> )
-	 *  qdtext         = <any TEXT except <">>
-	 *  quoted-pair    = "\" CHAR
-	 *
-	 * TEXT is any octet except CTLs, but including LWS;
-	 * LWS is [CR LF] 1*(SP | HT);
-	 * CHARs are ASCII octets 0-127;  (NOTE: we reject 0's)
-	 * CTLs are octets 0-31 and 127;
-	 */
-	if(*s != '"')
-		return s;
-
-	for(s++; 32 <= *s && *s < 127 && *s != '"'; s++)
-		if(*s == '\\' && *(s+1) != '\0')
-			s++;
-	return s;
-}
-
-static char*
-skiptoken(char *s)
-{
-	/*
-	 * Sec 2.2 of RFC2616 defines a "token" as
- 	 *  1*<any CHAR except CTLs or separators>;
-	 * CHARs are ASCII octets 0-127;
-	 * CTLs are octets 0-31 and 127;
-	 * separators are "()<>@,;:\/[]?={}", double-quote, SP (32), and HT (9)
-	 */
-	while(32 <= *s && *s < 127 && strchr("()<>@,;:[]?={}\" \t\\", *s)==nil)
-		s++;
-
-	return s;
-}
-
-static char*
-skipvalue(char *s, int isns)
-{
-	char *t;
-
-	/*
-	 * An RFC2109 value is an HTTP token or an HTTP quoted string.
-	 * Netscape servers ignore the spec and rely on semicolons, apparently.
-	 */
-	if(isns){
-		if((t = strchr(s, ';')) == nil)
-			t = s+strlen(s);
-		return t;
-	}
-	if(*s == '"')
-		return skipquoted(s);
-	return skiptoken(s);
-}
-
-/*
- * RMID=80b186bb64c03c65fab767f8; expires=Monday, 10-Feb-2003 04:44:39 GMT;
- *	path=/; domain=.nytimes.com
- */
-static char*
-parsecookie(Cookie *c, char *p, char **e, int isns, char *dom,
-	    char *path)
-{
-	int i, done;
-	char *t, *u, *attr, *val;
-
-	c->expire = ~0;
-	memset(c, 0, sizeof *c);
-
-	/* NAME=VALUE */
-	t = skiptoken(p);
-	c->name = p;
-	p = skipspace(t);
-	if(*p != '='){
-	Badname:
-		return "malformed cookie: no NAME=VALUE";
-	}
-	*t = '\0';
-	p = skipspace(p+1);
-	t = skipvalue(p, isns);
-	if(*t)
-		*t++ = '\0';
-	c->value = p;
-	p = skipspace(t);
-	if(c->name[0]=='\0' || c->value[0]=='\0')
-		goto Badname;
-
-	done = 0;
-	for(; *p && !done; p=skipspace(p)){
-		attr = p;
-		t = skiptoken(p);
-		u = skipspace(t);
-		switch(*u){
-		case '\0':
-			*t = '\0';
-			val = p = u;
-			break;
-		case ';':
-			*t = '\0';
-			val = "";
-			p = u+1;
-			break;
-		case '=':
-			*t = '\0';
-			val = skipspace(u+1);
-			p = skipvalue(val, isns);
-			if(*p==',')
-				done = 1;
-			if(*p)
-				*p++ = '\0';
-			break;
-		case ',':
-			if(!isns){
-				val = "";
-				p = u;
-				*p++ = '\0';
-				done = 1;
-				break;
-			}
-		default:
-			if(cookiedebug)
-				fprint(2, "syntax: %s\n", p);
-			return "syntax error";
-		}
-		for(i=0; i<nelem(stab); i++)
-			if(stab[i].ishttp && cistrcmp(stab[i].s, attr)==0)
-				*(char**)((uintptr)c+stab[i].offset) = val;
-		if(cistrcmp(attr, "expires") == 0){
-			if(!isns)
-				return "non-netscape cookie has Expires tag";
-			if(!val[0])
-				return "bad expires tag";
-			c->expire = strtotime(val);
-			if(c->expire == ~0)
-				return "cannot parse netscape expires tag";
-		}
-		if(cistrcmp(attr, "max-age") == 0)
-			c->expire = time(0)+atoi(val);
-		if(cistrcmp(attr, "secure") == 0)
-			c->secure = 1;
-	}
-
-	if(c->dom)
-		c->explicitdom = 1;
-	else
-		c->dom = dom;
-	if(c->path)
-		c->explicitpath = 1;
-	else{
-		c->path = path;
-		if((t = strchr(c->path, '?')) != 0)
-			*t = '\0';
-		if((t = strrchr(c->path, '/')) != 0)
-			*t = '\0';
-	}
-	c->netscapestyle = isns;
-	*e = p;
-
-	return nil;
-}
-
-Jar *jar;
-
-typedef struct Aux Aux;
-struct Aux
-{
-	char *dom;
-	char *path;
-	char *inhttp;
-	char *outhttp;
-	char *ctext;
-	int rdoff;
-};
-enum
-{
-	AuxBuf = 4096,
-	MaxCtext = 16*1024*1024,
-};
-
-void
-cookieopen(Req *r)
-{
-	char *s, *es;
-	int i, sz;
-	Aux *a;
-
-	syncjar(jar);
-	a = emalloc9p(sizeof(Aux));
-	r->fid->aux = a;
-	if(r->ifcall.mode&OTRUNC){
-		a->ctext = emalloc9p(1);
-		a->ctext[0] = '\0';
-	}else{
-		sz = 256*jar->nc+1024;	/* BUG should do better */
-		a->ctext = emalloc9p(sz);
-		a->ctext[0] = '\0';
-		s = a->ctext;
-		es = s+sz;
-		for(i=0; i<jar->nc; i++)
-			s = seprint(s, es, "%K\n", &jar->c[i]);
-	}
-	respond(r, nil);
-}
-
-void
-cookieread(Req *r)
-{
-	Aux *a;
-
-	a = r->fid->aux;
-	readstr(r, a->ctext);
-	respond(r, nil);
-}
-
-void
-cookiewrite(Req *r)
-{
-	Aux *a;
-	int sz;
-
-	a = r->fid->aux;
-	sz = r->ifcall.count+r->ifcall.offset;
-	if(sz > strlen(a->ctext)){
-		if(sz >= MaxCtext){
-			respond(r, "cookie file too large");
-			return;
-		}
-		a->ctext = erealloc9p(a->ctext, sz+1);
-		a->ctext[sz] = '\0';
-	}
-	memmove(a->ctext+r->ifcall.offset, r->ifcall.data, r->ifcall.count);
-	r->ofcall.count = r->ifcall.count;
-	respond(r, nil);
-}
-
-void
-cookieclunk(Fid *fid)
-{
-	char *p, *nextp;
-	Aux *a;
-	int i;
-
-	a = fid->aux;
-	if(a == nil)
-		return;
-	for(i=0; i<jar->nc; i++)
-		jar->c[i].mark = 1;
-	for(p=a->ctext; *p; p=nextp){
-		if((nextp = strchr(p, '\n')) != nil)
-			*nextp++ = '\0';
-		else
-			nextp = "";
-		addtojar(jar, p, 0);
-	}
-	for(i=0; i<jar->nc; i++)
-		if(jar->c[i].mark)
-			delcookie(jar, &jar->c[i]);
-	syncjar(jar);
-	free(a->dom);
-	free(a->path);
-	free(a->inhttp);
-	free(a->outhttp);
-	free(a->ctext);
-	free(a);
-}
-
-void
-closecookies(void)
-{
-	closejar(jar);
-}
-
-void
-initcookies(char *file)
-{
-	char *home;
-
-	fmtinstall('J', jarfmt);
-	fmtinstall('K', cookiefmt);
-
-	if(file == nil){
-		home = getenv("home");
-		if(home == nil)
-			sysfatal("no cookie file specified and no $home");
-		file = emalloc9p(strlen(home)+30);
-		strcpy(file, home);
-		strcat(file, "/lib/webcookies");
-	}
-	jar = readjar(file);
-	if(jar == nil)
-		sysfatal("readjar: %r");
-}
-
-void
-httpsetcookie(char *hdr, char *dom, char *path)
-{
-	if(path == nil)
-		path = "/";
-
-	parsehttp(jar, hdr, dom, path);
-	syncjar(jar);
-}
-
-char*
-httpcookies(char *dom, char *path, int issecure)
-{
-	char buf[1024];
-	Jar *j;
-
-	syncjar(jar);
-	j = cookiesearch(jar, dom, path, issecure);
-	snprint(buf, sizeof buf, "%J", j);
-	closejar(j);
-	return estrdup(buf);
-}

+ 0 - 111
sys/src/cmd/webfs/dat.h

@@ -1,111 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-typedef struct Client Client;
-typedef struct Ctl Ctl;
-typedef struct Ibuf Ibuf;
-typedef struct Url Url;
-
-/* simple buffered i/o for network connections; shared by http, ftp */
-struct Ibuf
-{
-	int fd;
-	Ioproc *io;
-	char buf[4096];
-	char *rp, *wp;
-};
-
-struct Ctl
-{
-	int	acceptcookies;
-	int	sendcookies;
-	int	redirectlimit;
-	char	*useragent;
-};
-
-struct Client
-{
-	Url	*url;
-	Url	*baseurl;
-	Ctl ctl;
-	Channel *creq;	/* chan(Req*) */
-	int num;
-	int plumbed;
-	char *contenttype;
-	char *postbody;
-	char *redirect;
-	char *authenticate;
-	char *ext;
-	int npostbody;
-	int havepostbody;
-	int iobusy;
-	int bodyopened;
-	Ioproc *io;
-	int ref;
-	void *aux;
-};
-
-/*
- * If ischeme is USunknown, then the given URL is a relative
- * URL which references the "current document" in the context of the base.
- * If this is the case, only the "fragment" and "url" members will have
- * meaning, and the given URL structure may not be used as a base URL itself.
- */
-enum
-{
-	USunknown,
-	UShttp,
-	UShttps,
-	USftp,
-	USfile,
-	UScurrent,
-};
-
-struct Url
-{
-	int		ischeme;
-	char*	url;
-	char*	scheme;
-	int		(*open)(Client*, Url*);
-	int		(*read)(Client*, Req*);
-	void		(*close)(Client*);
-	char*	schemedata;
-	char*	authority;
-	char*	user;
-	char*	passwd;
-	char*	host;
-	char*	port;
-	char*	path;
-	char*	query;
-	char*	fragment;
-	union {
-		struct {
-			char *page_spec;
-		} http;
-		struct {
-			char *path_spec;
-			char *type;
-		} ftp;
-	};
-};
-
-enum
-{
-	STACK = 32*1024,  /* was 16*1024; there are big arrays on the stack */
-};
-
-extern	Client**	client;
-extern	int		cookiedebug;
-extern	Srv		fs;
-extern	int		fsdebug;
-extern	Ctl		globalctl;
-extern	int		nclient;
-extern	int		urldebug;
-extern	int		httpdebug;
-extern	char*	status[];

+ 0 - 71
sys/src/cmd/webfs/fns.h

@@ -1,71 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-/* buf.c */
-void		initibuf(Ibuf*, Ioproc*, int);
-int		readibuf(Ibuf*, char*, int);
-void		unreadline(Ibuf*, char*);
-int		readline(Ibuf*, char*, int);
-
-/* client.c */
-int		newclient(int);
-void		closeclient(Client*);
-void		clonectl(Ctl*);
-int		ctlwrite(Req*, Ctl*, char*, char*);
-int		clientctlwrite(Req*, Client*, char*, char*);
-int		globalctlwrite(Req*, char*, char*);
-void		ctlread(Req*, Client*);
-void		globalctlread(Req*);
-void		plumburl(char*, char*);
-
-/* cookies.c */
-void		cookieread(Req*);
-void		cookiewrite(Req*);
-void		cookieopen(Req*);
-void		cookieclunk(Fid*);
-void		initcookies(char*);
-void		closecookies(void);
-void		httpsetcookie(char*, char*, char*);
-char*	httpcookies(char*, char*, int);
-
-/* fs.c */
-void		initfs(void);
-
-/* http.c */
-int		httpopen(Client*, Url*);
-int		httpread(Client*, Req*);
-void		httpclose(Client*);
-
-/* io.c */
-int		iotlsdial(Ioproc*, char*, char*, char*, int*, int);
-int		ioprint(Ioproc*, int, char*, ...);
-//#pragma varargck argpos ioprint 3
-
-/* plumb.c */
-void	plumbinit(void);
-void	plumbstart(void);
-void	replumb(Client*);
-
-/* url.c */
-Url*		parseurl(char*, Url*);
-void		freeurl(Url*);
-void		rewriteurl(Url*);
-int		seturlquery(Url*, char*);
-Url*		copyurl(Url*);
-char*	escapeurl(char*, int(*)(int));
-char*	unescapeurl(char*);
-void		initurl(void);
-
-/* util.c */
-char*	estrdup(char*);
-char*	estrmanydup(char*, ...);
-char*	estredup(char*, char*);
-void*	emalloc(uint);
-void*	erealloc(void*, uint);
-char*	strlower(char*);

+ 0 - 625
sys/src/cmd/webfs/fs.c

@@ -1,625 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-/*
- * Web file system.  Conventionally mounted at /mnt/web
- *
- *	ctl				send control messages (might go away)
- *	cookies			list of cookies, editable
- *	clone			open and read to obtain new connection
- *	n				connection directory
- *		ctl				control messages (like get url)
- *		body				retrieved data
- *		content-type		mime content-type of body
- *		postbody			data to be posted
- *		parsed			parsed version of url
- * 			url				entire url
- *			scheme			http, ftp, etc.
- *			host				hostname
- *			path				path on host
- *			query			query after path
- *			fragment			#foo anchor reference
- *			user				user name (ftp)
- *			password			password (ftp)
- *			ftptype			transfer mode (ftp)
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ip.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include "dat.h"
-#include "fns.h"
-
-int fsdebug;
-
-enum
-{
-	Qroot,
-	Qrootctl,
-	Qclone,
-	Qcookies,
-	Qclient,
-	Qctl,
-	Qbody,
-	Qbodyext,
-	Qcontenttype,
-	Qpostbody,
-	Qparsed,
-	Qurl,
-	Qscheme,
-	Qschemedata,
-	Quser,
-	Qpasswd,
-	Qhost,
-	Qport,
-	Qpath,
-	Qquery,
-	Qfragment,
-	Qftptype,
-	Qend,
-};
-
-#define PATH(type, n)	((type)|((n)<<8))
-#define TYPE(path)		((int)(path) & 0xFF)
-#define NUM(path)		((uint)(path)>>8)
-
-Channel *creq;
-Channel *creqwait;
-Channel *cclunk;
-Channel *cclunkwait;
-
-typedef struct Tab Tab;
-struct Tab
-{
-	char *name;
-	uint32_t mode;
-	int offset;
-};
-
-Tab tab[] =
-{
-	"/",			DMDIR|0555,		0,
-	"ctl",			0666,			0,
-	"clone",		0666,			0,
-	"cookies",		0666,			0,
-	"XXX",		DMDIR|0555,		0,
-	"ctl",			0666,			0,
-	"body",		0444,			0,
-	"XXX",		0444,			0,
-	"contenttype",	0444,			0,
-	"postbody",	0666,			0,
-	"parsed",		DMDIR|0555,		0,
-	"url",			0444,			offsetof(Url, url),
-	"scheme",		0444,			offsetof(Url, scheme),
-	"schemedata",	0444,			offsetof(Url, schemedata),
-	"user",		0444,			offsetof(Url, user),
-	"passwd",		0444,			offsetof(Url, passwd),
-	"host",		0444,			offsetof(Url, host),
-	"port",		0444,			offsetof(Url, port),
-	"path",		0444,			offsetof(Url, path),
-	"query",		0444,			offsetof(Url, query),
-	"fragment",	0444,			offsetof(Url, fragment),
-	"ftptype",		0444,			offsetof(Url, ftp.type),
-};
-
-uint32_t time0;
-
-static void
-fillstat(Dir *d, uint64_t path, uint32_t length, char *ext)
-{
-	Tab *t;
-	int type;
-	char buf[32];
-
-	memset(d, 0, sizeof(*d));
-	d->uid = estrdup("web");
-	d->gid = estrdup("web");
-	d->qid.path = path;
-	d->atime = d->mtime = time0;
-	d->length = length;
-	type = TYPE(path);
-	t = &tab[type];
-	if(type == Qbodyext) {
-		snprint(buf, sizeof buf, "body.%s", ext == nil ? "xxx" : ext);
-		d->name = estrdup(buf);
-	}
-	else if(t->name)
-		d->name = estrdup(t->name);
-	else{	/* client directory */
-		snprint(buf, sizeof buf, "%u", NUM(path));
-		d->name = estrdup(buf);
-	}
-	d->qid.type = t->mode>>24;
-	d->mode = t->mode;
-}
-
-static void
-fsstat(Req *r)
-{
-	fillstat(&r->d, r->fid->qid.path, 0, nil);
-	respond(r, nil);
-}
-
-static int
-rootgen(int i, Dir *d, void*)
-{
-	char buf[32];
-
-	i += Qroot+1;
-	if(i < Qclient){
-		fillstat(d, i, 0, nil);
-		return 0;
-	}
-	i -= Qclient;
-	if(i < nclient){
-		fillstat(d, PATH(Qclient, i), 0, nil);
-		snprint(buf, sizeof buf, "%d", i);
-		free(d->name);
-		d->name = estrdup(buf);
-		return 0;
-	}
-	return -1;
-}
-
-static int
-clientgen(int i, Dir *d, void *aux)
-{
-	Client *c;
-
-	c = aux;
-	i += Qclient+1;
-	if(i <= Qparsed){
-		fillstat(d, PATH(i, c->num), 0, c->ext);
-		return 0;
-	}
-	return -1;
-}
-
-static int
-parsedgen(int i, Dir *d, void *aux)
-{
-	Client *c;
-
-	c = aux;
-	i += Qparsed+1;
-	if(i < Qend){
-		fillstat(d, PATH(i, c->num), 0, nil);
-		return 0;
-	}
-	return -1;
-}
-
-static void
-fsread(Req *r)
-{
-	char *s;
-	char e[ERRMAX];
-	Client *c;
-	uint32_t path;
-
-	path = r->fid->qid.path;
-	switch(TYPE(path)){
-	default:
-		snprint(e, sizeof e, "bug in webfs path=%lx\n", path);
-		respond(r, e);
-		break;
-
-	case Qroot:
-		dirread9p(r, rootgen, nil);
-		respond(r, nil);
-		break;
-
-	case Qrootctl:
-		globalctlread(r);
-		break;
-
-	case Qcookies:
-		cookieread(r);
-		break;
-
-	case Qclient:
-		dirread9p(r, clientgen, client[NUM(path)]);
-		respond(r, nil);
-		break;
-
-	case Qctl:
-		ctlread(r, client[NUM(path)]);
-		break;
-
-	case Qcontenttype:
-		c = client[NUM(path)];
-		if(c->contenttype == nil)
-			r->ofcall.count = 0;
-		else
-			readstr(r, c->contenttype);
-		respond(r, nil);
-		break;
-
-	case Qpostbody:
-		c = client[NUM(path)];
-		readbuf(r, c->postbody, c->npostbody);
-		respond(r, nil);
-		break;
-
-	case Qbody:
-	case Qbodyext:
-		c = client[NUM(path)];
-		if(c->iobusy){
-			respond(r, "already have i/o pending");
-			break;
-		}
-		c->iobusy = 1;
-		sendp(c->creq, r);
-		break;
-
-	case Qparsed:
-		dirread9p(r, parsedgen, client[NUM(path)]);
-		respond(r, nil);
-		break;
-
-	case Qurl:
-	case Qscheme:
-	case Qschemedata:
-	case Quser:
-	case Qpasswd:
-	case Qhost:
-	case Qport:
-	case Qpath:
-	case Qquery:
-	case Qfragment:
-	case Qftptype:
-		c = client[NUM(path)];
-		r->ofcall.count = 0;
-		if(c->url != nil
-		&& (s = *(char**)((uintptr)c->url+tab[TYPE(path)].offset)) != nil)
-			readstr(r, s);
-		respond(r, nil);
-		break;
-	}
-}
-
-static void
-fswrite(Req *r)
-{
-	int m;
-	uint32_t path;
-	char e[ERRMAX], *buf, *cmd, *arg;
-	Client *c;
-
-	path = r->fid->qid.path;
-	switch(TYPE(path)){
-	default:
-		snprint(e, sizeof e, "bug in webfs path=%lx\n", path);
-		respond(r, e);
-		break;
-
-	case Qcookies:
-		cookiewrite(r);
-		break;
-
-	case Qrootctl:
-	case Qctl:
-		if(r->ifcall.count >= 1024){
-			respond(r, "ctl message too long");
-			return;
-		}
-		buf = estredup(r->ifcall.data,
-			       (char*)r->ifcall.data+r->ifcall.count);
-		cmd = buf;
-		arg = strpbrk(cmd, "\t ");
-		if(arg){
-			*arg++ = '\0';
-			arg += strspn(arg, "\t ");
-		}else
-			arg = "";
-		r->ofcall.count = r->ifcall.count;
-		if(TYPE(path)==Qrootctl){
-			if(!ctlwrite(r, &globalctl, cmd, arg)
-			&& !globalctlwrite(r, cmd, arg))
-				respond(r, "unknown control command");
-		}else{
-			c = client[NUM(path)];
-			if(!ctlwrite(r, &c->ctl, cmd, arg)
-			&& !clientctlwrite(r, c, cmd, arg))
-				respond(r, "unknown control command");
-		}
-		free(buf);
-		break;
-
-	case Qpostbody:
-		c = client[NUM(path)];
-		if(c->bodyopened){
-			respond(r, "cannot write postbody after opening body");
-			break;
-		}
-		if(r->ifcall.offset >= 128*1024*1024){	/* >128MB is probably a mistake */
-			respond(r, "offset too large");
-			break;
-		}
-		m = r->ifcall.offset + r->ifcall.count;
-		if(c->npostbody < m){
-			c->postbody = erealloc(c->postbody, m);
-			memset(c->postbody+c->npostbody, 0, m-c->npostbody);
-			c->npostbody = m;
-		}
-		memmove(c->postbody+r->ifcall.offset, r->ifcall.data, r->ifcall.count);
-		r->ofcall.count = r->ifcall.count;
-		respond(r, nil);
-		break;
-	}
-}
-
-static void
-fsopen(Req *r)
-{
-	static int need[4] = { 4, 2, 6, 1 };
-	uint32_t path;
-	int n;
-	Client *c;
-	Tab *t;
-
-	/*
-	 * lib9p already handles the blatantly obvious.
-	 * we just have to enforce the permissions we have set.
-	 */
-	path = r->fid->qid.path;
-	t = &tab[TYPE(path)];
-	n = need[r->ifcall.mode&3];
-	if((n&t->mode) != n){
-		respond(r, "permission denied");
-		return;
-	}
-
-	switch(TYPE(path)){
-	case Qcookies:
-		cookieopen(r);
-		break;
-
-	case Qpostbody:
-		c = client[NUM(path)];
-		c->havepostbody++;
-		c->ref++;
-		respond(r, nil);
-		break;
-
-	case Qbody:
-	case Qbodyext:
-		c = client[NUM(path)];
-		if(c->url == nil){
-			respond(r, "url is not yet set");
-			break;
-		}
-		c->bodyopened = 1;
-		c->ref++;
-		sendp(c->creq, r);
-		break;
-
-	case Qclone:
-		n = newclient(0);
-		path = PATH(Qctl, n);
-		r->fid->qid.path = path;
-		r->ofcall.qid.path = path;
-		if(fsdebug)
-			fprint(2, "open clone => path=%lx\n", path);
-		t = &tab[Qctl];
-		/* fall through */
-	default:
-		if(t-tab >= Qclient)
-			client[NUM(path)]->ref++;
-		respond(r, nil);
-		break;
-	}
-}
-
-static void
-fsdestroyfid(Fid *fid)
-{
-	sendp(cclunk, fid);
-	recvp(cclunkwait);
-}
-
-static void
-fsattach(Req *r)
-{
-	if(r->ifcall.aname && r->ifcall.aname[0]){
-		respond(r, "invalid attach specifier");
-		return;
-	}
-	r->fid->qid.path = PATH(Qroot, 0);
-	r->fid->qid.type = QTDIR;
-	r->fid->qid.vers = 0;
-	r->ofcall.qid = r->fid->qid;
-	respond(r, nil);
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{
-	int i, n;
-	uint32_t path;
-	char buf[32], *ext;
-
-	path = fid->qid.path;
-	if(!(fid->qid.type&QTDIR))
-		return "walk in non-directory";
-
-	if(strcmp(name, "..") == 0){
-		switch(TYPE(path)){
-		case Qparsed:
-			qid->path = PATH(Qclient, NUM(path));
-			qid->type = tab[Qclient].mode>>24;
-			return nil;
-		case Qclient:
-		case Qroot:
-			qid->path = PATH(Qroot, 0);
-			qid->type = tab[Qroot].mode>>24;
-			return nil;
-		default:
-			return "bug in fswalk1";
-		}
-	}
-
-	i = TYPE(path)+1;
-	for(; i<nelem(tab); i++){
-		if(i==Qclient){
-			n = atoi(name);
-			snprint(buf, sizeof buf, "%d", n);
-			if(n < nclient && strcmp(buf, name) == 0){
-				qid->path = PATH(i, n);
-				qid->type = tab[i].mode>>24;
-				return nil;
-			}
-			break;
-		}
-		if(i==Qbodyext){
-			ext = client[NUM(path)]->ext;
-			snprint(buf, sizeof buf, "body.%s", ext == nil ? "xxx" : ext);
-			if(strcmp(buf, name) == 0){
-				qid->path = PATH(i, NUM(path));
-				qid->type = tab[i].mode>>24;
-				return nil;
-			}
-		}
-		else if(strcmp(name, tab[i].name) == 0){
-			qid->path = PATH(i, NUM(path));
-			qid->type = tab[i].mode>>24;
-			return nil;
-		}
-		if(tab[i].mode&DMDIR)
-			break;
-	}
-	return "directory entry not found";
-}
-
-static void
-fsflush(Req *r)
-{
-	Req *or;
-	int t;
-	Client *c;
-	uint32_t path;
-
-	or=r;
-	while(or->ifcall.type==Tflush)
-		or = or->oldreq;
-
-	if(or->ifcall.type != Tread && or->ifcall.type != Topen)
-		abort();
-
-	path = or->fid->qid.path;
-	t = TYPE(path);
-	if(t != Qbody && t != Qbodyext)
-		abort();
-
-	c = client[NUM(path)];
-	sendp(c->creq, r);
-	iointerrupt(c->io);
-}
-
-static void
-fsthread(void*)
-{
-	uint32_t path;
-	Alt a[3];
-	Fid *fid;
-	Req *r;
-
-	threadsetname("fsthread");
-	plumbstart();
-
-	a[0].op = CHANRCV;
-	a[0].c = cclunk;
-	a[0].v = &fid;
-	a[1].op = CHANRCV;
-	a[1].c = creq;
-	a[1].v = &r;
-	a[2].op = CHANEND;
-
-	for(;;){
-		switch(alt(a)){
-		case 0:
-			path = fid->qid.path;
-			if(TYPE(path)==Qcookies)
-				cookieclunk(fid);
-			if(fid->omode != -1 && TYPE(path) >= Qclient)
-				closeclient(client[NUM(path)]);
-			sendp(cclunkwait, nil);
-			break;
-		case 1:
-			switch(r->ifcall.type){
-			case Tattach:
-				fsattach(r);
-				break;
-			case Topen:
-				fsopen(r);
-				break;
-			case Tread:
-				fsread(r);
-				break;
-			case Twrite:
-				fswrite(r);
-				break;
-			case Tstat:
-				fsstat(r);
-				break;
-			case Tflush:
-				fsflush(r);
-				break;
-			default:
-				respond(r, "bug in fsthread");
-				break;
-			}
-			sendp(creqwait, 0);
-			break;
-		}
-	}
-}
-
-static void
-fssend(Req *r)
-{
-	sendp(creq, r);
-	recvp(creqwait);	/* avoids need to deal with spurious flushes */
-}
-
-void
-initfs(void)
-{
-	time0 = time(0);
-	creq = chancreate(sizeof(void*), 0);
-	creqwait = chancreate(sizeof(void*), 0);
-	cclunk = chancreate(sizeof(void*), 0);
-	cclunkwait = chancreate(sizeof(void*), 0);
-	procrfork(fsthread, nil, STACK, RFNAMEG);
-}
-
-void
-takedown(Srv*)
-{
-	closecookies();
-	threadexitsall("done");
-}
-
-Srv fs =
-{
-.attach=		fssend,
-.destroyfid=	fsdestroyfid,
-.walk1=		fswalk1,
-.open=		fssend,
-.read=		fssend,
-.write=		fssend,
-.stat=		fssend,
-.flush=		fssend,
-.end=		takedown,
-};

+ 0 - 548
sys/src/cmd/webfs/http.c

@@ -1,548 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ip.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include <libsec.h>
-#include <auth.h>
-#include "dat.h"
-#include "fns.h"
-
-char PostContentType[] = "application/x-www-form-urlencoded";
-int httpdebug;
-
-typedef struct HttpState HttpState;
-struct HttpState
-{
-	int fd;
-	Client *c;
-	char *location;
-	char *setcookie;
-	char *netaddr;
-	char *credentials;
-	char autherror[ERRMAX];
-	Ibuf	b;
-};
-
-static void
-location(HttpState *hs, char *value)
-{
-	if(hs->location == nil)
-		hs->location = estrdup(value);
-}
-
-static void
-contenttype(HttpState *hs, char *value)
-{
-	if(hs->c->contenttype != nil)
-		free(hs->c->contenttype);
-	hs->c->contenttype = estrdup(value);
-}
-
-static void
-setcookie(HttpState *hs, char *value)
-{
-	char *s, *t;
-	Fmt f;
-
-	s = hs->setcookie;
-	fmtstrinit(&f);
-	if(s)
-		fmtprint(&f, "%s", s);
-	fmtprint(&f, "set-cookie: ");
-	fmtprint(&f, "%s", value);
-	fmtprint(&f, "\n");
-	t = fmtstrflush(&f);
-	if(t){
-		free(s);
-		hs->setcookie = t;
-	}
-}
-
-static char*
-unquote(char *s, char **ps)
-{
-	char *p;
-
-	if(*s != '"'){
-		p = strpbrk(s, " \t\r\n");
-		*p++ = 0;
-		*ps = p;
-		return s;
-	}
-	for(p=s+1; *p; p++){
-		if(*p == '\"'){
-			*p++ = 0;
-			break;
-		}
-		if(*p == '\\' && *(p+1)){
-			p++;
-			continue;
-		}
-	}
-	memmove(s, s+1, p-(s+1));
-	s[p-(s+1)] = 0;
-	*ps = p;
-	return s;
-}
-
-static char*
-servername(char *addr)
-{
-	char *p;
-
-	if(strncmp(addr, "tcp!", 4) == 0
-	|| strncmp(addr, "net!", 4) == 0)
-		addr += 4;
-	addr = estrdup(addr);
-	p = addr+strlen(addr);
-	if(p>addr && *(p-1) == 's')
-		p--;
-	if(p>addr+5 && strcmp(p-5, "!http") == 0)
-		p[-5] = 0;
-	return addr;
-}
-
-void
-wwwauthenticate(HttpState *hs, char *line)
-{
-	char cred[64], *user, *pass, *realm, *s, *spec, *name;
-	Fmt fmt;
-	UserPasswd *up;
-
-	spec = nil;
-	up = nil;
-	cred[0] = 0;
-	hs->autherror[0] = 0;
-	if(cistrncmp(line, "basic ", 6) != 0){
-		werrstr("unknown auth: %s", line);
-		goto error;
-	}
-	line += 6;
-	if(cistrncmp(line, "realm=", 6) != 0){
-		werrstr("missing realm: %s", line);
-		goto error;
-	}
-	line += 6;
-	user = hs->c->url->user;
-	pass = hs->c->url->passwd;
-	if(user==nil || pass==nil){
-		realm = unquote(line, &line);
-		fmtstrinit(&fmt);
-		name = servername(hs->netaddr);
-		fmtprint(&fmt, "proto=pass service=http server=%q realm=%q", name, realm);
-		free(name);
-		if(hs->c->url->user)
-			fmtprint(&fmt, " user=%q", hs->c->url->user);
-		spec = fmtstrflush(&fmt);
-		if(spec == nil)
-			goto error;
-		if((up = auth_getuserpasswd(nil, "%s", spec)) == nil)
-			goto error;
-		user = up->user;
-		pass = up->passwd;
-	}
-	if((s = smprint("%s:%s", user, pass)) == nil)
-		goto error;
-	free(up);
-	enc64(cred, sizeof(cred), (uint8_t*)s, strlen(s));
-	memset(s, 0, strlen(s));
-	free(s);
-	hs->credentials = smprint("Basic %s", cred);
-	if(hs->credentials == nil)
-		goto error;
-	return;
-
-error:
-	free(up);
-	free(spec);
-	snprint(hs->autherror, sizeof hs->autherror, "%r");
-	fprint(2, "%s: Authentication failed: %r\n", argv0);
-}
-
-struct {
-	char *name;									/* Case-insensitive */
-	void (*fn)(HttpState *hs, char *value);
-} hdrtab[] = {
-	{ "location:", location },
-	{ "content-type:", contenttype },
-	{ "set-cookie:", setcookie },
-	{ "www-authenticate:", wwwauthenticate },
-};
-
-static int
-httprcode(HttpState *hs)
-{
-	int n;
-	char *p;
-	char buf[256];
-
-	n = readline(&hs->b, buf, sizeof(buf)-1);
-	if(n <= 0)
-		return n;
-	if(httpdebug)
-		fprint(2, "-> %s\n", buf);
-	p = strchr(buf, ' ');
-	if(memcmp(buf, "HTTP/", 5) != 0 || p == nil){
-		werrstr("bad response from server");
-		return -1;
-	}
-	buf[n] = 0;
-	return atoi(p+1);
-}
-
-/*
- *  read a single mime header, collect continuations.
- *
- *  this routine assumes that there is a blank line twixt
- *  the header and the message body, otherwise bytes will
- *  be lost.
- */
-static int
-getheader(HttpState *hs, char *buf, int n)
-{
-	char *p, *e;
-	int i;
-
-	n--;
-	p = buf;
-	for(e = p + n; ; p += i){
-		i = readline(&hs->b, p, e-p);
-		if(i < 0)
-			return i;
-
-		if(p == buf){
-			/* first line */
-			if(strchr(buf, ':') == nil)
-				break;		/* end of headers */
-		} else {
-			/* continuation line */
-			if(*p != ' ' && *p != '\t'){
-				unreadline(&hs->b, p);
-				*p = 0;
-				break;		/* end of this header */
-			}
-		}
-	}
-
-	if(httpdebug)
-		fprint(2, "-> %s\n", buf);
-	return p-buf;
-}
-
-static int
-httpheaders(HttpState *hs)
-{
-	char buf[2048];
-	char *p;
-	int i, n;
-
-	for(;;){
-		n = getheader(hs, buf, sizeof(buf));
-		if(n < 0)
-			return -1;
-		if(n == 0)
-			return 0;
-		//	print("http header: '%.*s'\n", n, buf);
-		for(i = 0; i < nelem(hdrtab); i++){
-			n = strlen(hdrtab[i].name);
-			if(cistrncmp(buf, hdrtab[i].name, n) == 0){
-				/* skip field name and leading white */
-				p = buf + n;
-				while(*p == ' ' || *p == '\t')
-					p++;
-				(*hdrtab[i].fn)(hs, p);
-				break;
-			}
-		}
-	}
-}
-
-int
-httpopen(Client *c, Url *url)
-{
-	int fd, code, redirect, authenticate;
-	char *cookies;
-	Ioproc *io;
-	HttpState *hs;
-	char *service;
-
-	if(httpdebug)
-		fprint(2, "httpopen\n");
-	io = c->io;
-	hs = emalloc(sizeof(*hs));
-	hs->c = c;
-
-	if(url->port)
-		service = url->port;
-	else
-		service = url->scheme;
-	hs->netaddr = estrdup(netmkaddr(url->host, 0, service));
-	c->aux = hs;
-	if(httpdebug){
-		fprint(2, "dial %s\n", hs->netaddr);
-		fprint(2, "dial port: %s\n", url->port);
-	}
-	fd = iotlsdial(io, hs->netaddr, 0, 0, 0, url->ischeme==UShttps);
-	if(fd < 0){
-	Error:
-		if(httpdebug)
-			fprint(2, "iodial: %r\n");
-		free(hs->location);
-		free(hs->setcookie);
-		free(hs->netaddr);
-		free(hs->credentials);
-		if(fd >= 0)
-			ioclose(io, hs->fd);
-		hs->fd = -1;
-		free(hs);
-		c->aux = nil;
-		return -1;
-	}
-	hs->fd = fd;
-	if(httpdebug)
-		fprint(2, "<- %s %s HTTP/1.0\n<- Host: %s\n",
-			c->havepostbody? "POST": "GET", url->http.page_spec, url->host);
-	ioprint(io, fd, "%s %s HTTP/1.0\r\nHost: %s\r\n",
-		c->havepostbody? "POST" : "GET", url->http.page_spec, url->host);
-	if(httpdebug)
-		fprint(2, "<- User-Agent: %s\n", c->ctl.useragent);
-	if(c->ctl.useragent)
-		ioprint(io, fd, "User-Agent: %s\r\n", c->ctl.useragent);
-	if(c->ctl.sendcookies){
-		/* should we use url->page here?  sometimes it is nil. */
-		cookies = httpcookies(url->host, url->http.page_spec,
-			url->ischeme == UShttps);
-		if(cookies && cookies[0])
-			ioprint(io, fd, "%s", cookies);
-		if(httpdebug)
-			fprint(2, "<- %s", cookies);
-		free(cookies);
-	}
-	if(c->havepostbody){
-		ioprint(io, fd, "Content-type: %s\r\n", PostContentType);
-		ioprint(io, fd, "Content-length: %u\r\n", c->npostbody);
-		if(httpdebug){
-			fprint(2, "<- Content-type: %s\n", PostContentType);
-			fprint(2, "<- Content-length: %u\n", c->npostbody);
-		}
-	}
-	if(c->authenticate){
-		ioprint(io, fd, "Authorization: %s\r\n", c->authenticate);
-		if(httpdebug)
-			fprint(2, "<- Authorization: %s\n", c->authenticate);
-	}
-	ioprint(io, fd, "\r\n");
-	if(c->havepostbody)
-		if(iowrite(io, fd, c->postbody, c->npostbody) != c->npostbody)
-			goto Error;
-
-	redirect = 0;
-	authenticate = 0;
-	initibuf(&hs->b, io, fd);
-	code = httprcode(hs);
-
-	switch(code){
-	case -1:	/* connection timed out */
-		goto Error;
-
-/*
-	case Eof:
-		werrstr("EOF from HTTP server");
-		goto Error;
-*/
-
-	case 200:	/* OK */
-	case 201:	/* Created */
-	case 202:	/* Accepted */
-	case 204:	/* No Content */
-	case 205: /* Reset Content */
-#ifdef NOT_DEFINED
-		if(ofile == nil && r->start != 0)
-			sysfatal("page changed underfoot");
-#endif
-		break;
-
-	case 206:	/* Partial Content */
-		werrstr("Partial Content (206)");
-		goto Error;
-
-	case 301:	/* Moved Permanently */
-	case 302:	/* Moved Temporarily */
-	case 303:	/* See Other */
-	case 307: /* Temporary Redirect  */
-		redirect = 1;
-		break;
-
-	case 304:	/* Not Modified */
-		break;
-
-	case 400:	/* Bad Request */
-		werrstr("Bad Request (400)");
-		goto Error;
-
-	case 401:	/* Unauthorized */
-		if(c->authenticate){
-			werrstr("Authentication failed (401)");
-			goto Error;
-		}
-		authenticate = 1;
-		break;
-	case 402:	/* Payment Required */
-		werrstr("Payment Required (402)");
-		goto Error;
-
-	case 403:	/* Forbidden */
-		werrstr("Forbidden by server (403)");
-		goto Error;
-
-	case 404:	/* Not Found */
-		werrstr("Not found on server (404)");
-		goto Error;
-
-	case 405:	/* Method Not Allowed  */
-		werrstr("Method not allowed (405)");
-		goto Error;
-
-	case 406: /* Not Acceptable */
-		werrstr("Not Acceptable (406)");
-		goto Error;
-
-	case 407:	/* Proxy auth */
-		werrstr("Proxy authentication required (407)");
-		goto Error;
-
-	case 408: /* Request Timeout */
-		werrstr("Request Timeout (408)");
-		goto Error;
-
-	case 409: /* Conflict */
-		werrstr("Conflict  (409)");
-		goto Error;
-
-	case 410: /* Gone */
-		werrstr("Gone  (410)");
-		goto Error;
-
-	case 411: /* Length Required */
-		werrstr("Length Required  (411)");
-		goto Error;
-
-	case 412: /* Precondition Failed */
-		werrstr("Precondition Failed  (412)");
-		goto Error;
-
-	case 413: /* Request Entity Too Large */
-		werrstr("Request Entity Too Large  (413)");
-		goto Error;
-
-	case 414: /* Request-URI Too Long */
-		werrstr("Request-URI Too Long  (414)");
-		goto Error;
-
-	case 415: /* Unsupported Media Type */
-		werrstr("Unsupported Media Type  (415)");
-		goto Error;
-
-	case 416: /* Requested Range Not Satisfiable */
-		werrstr("Requested Range Not Satisfiable  (416)");
-		goto Error;
-
-	case 417: /* Expectation Failed */
-		werrstr("Expectation Failed  (417)");
-		goto Error;
-
-	case 500:	/* Internal server error */
-		werrstr("Server choked (500)");
-		goto Error;
-
-	case 501:	/* Not implemented */
-		werrstr("Server can't do it (501)");
-		goto Error;
-
-	case 502:	/* Bad gateway */
-		werrstr("Bad gateway (502)");
-		goto Error;
-
-	case 503:	/* Service unavailable */
-		werrstr("Service unavailable (503)");
-		goto Error;
-
-	default:
-		/* Bogus: we should treat unknown code XYZ as code X00 */
-		werrstr("Unknown response code %d", code);
-		goto Error;
-	}
-
-	if(httpheaders(hs) < 0)
-		goto Error;
-	if(c->ctl.acceptcookies && hs->setcookie)
-		httpsetcookie(hs->setcookie, url->host, url->path);
-	if(authenticate){
-		if(!hs->credentials){
-			if(hs->autherror[0])
-				werrstr("%s", hs->autherror);
-			else
-				werrstr("unauthorized; no www-authenticate: header");
-			goto Error;
-		}
-		c->authenticate = hs->credentials;
-		hs->credentials = nil;
-	}else if(c->authenticate)
-		c->authenticate = 0;
-	if(redirect){
-		if(!hs->location){
-			werrstr("redirection without Location: header");
-			goto Error;
-		}
-		c->redirect = hs->location;
-		hs->location = nil;
-	}
-	return 0;
-}
-
-int
-httpread(Client *c, Req *r)
-{
-	HttpState *hs;
-	int32_t n;
-
-	hs = c->aux;
-	n = readibuf(&hs->b, r->ofcall.data, r->ifcall.count);
-	if(n < 0)
-		return -1;
-
-	r->ofcall.count = n;
-	return 0;
-}
-
-void
-httpclose(Client *c)
-{
-	HttpState *hs;
-
-	hs = c->aux;
-	if(hs == nil)
-		return;
-	if(hs->fd >= 0)
-		ioclose(c->io, hs->fd);
-	hs->fd = -1;
-	free(hs->location);
-	free(hs->setcookie);
-	free(hs->netaddr);
-	free(hs->credentials);
-	free(hs);
-	c->aux = nil;
-}

+ 0 - 94
sys/src/cmd/webfs/io.c

@@ -1,94 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ip.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include <mp.h>
-#include <libsec.h>
-#include "dat.h"
-#include "fns.h"
-
-static int32_t
-_iovfprint(va_list *arg)
-{
-	int fd;
-	char *fmt;
-	va_list arg2;
-
-	fd = va_arg(*arg, int);
-	fmt = va_arg(*arg, char*);
-	arg2 = va_arg(*arg, va_list);
-	return vfprint(fd, fmt, arg2);
-}
-
-int
-iovfprint(Ioproc *io, int fd, char *fmt, va_list arg)
-{
-	return iocall(io, _iovfprint, fd, fmt, arg);
-}
-
-int
-ioprint(Ioproc *io, int fd, char *fmt, ...)
-{
-	int n;
-	va_list arg;
-
-	va_start(arg, fmt);
-	n = iovfprint(io, fd, fmt, arg);
-	va_end(arg);
-	return n;
-}
-
-static int32_t
-_iotlsdial(va_list *arg)
-{
-	char *addr, *local, *dir;
-	int *cfdp, fd, tfd, usetls;
-	TLSconn conn;
-
-	addr = va_arg(*arg, char*);
-	local = va_arg(*arg, char*);
-	dir = va_arg(*arg, char*);
-	cfdp = va_arg(*arg, int*);
-	usetls = va_arg(*arg, int);
-
-	fd = dial(addr, local, dir, cfdp);
-	if(fd < 0)
-		return -1;
-	if(!usetls)
-		return fd;
-
-	memset(&conn, 0, sizeof conn);
-	/* does no good, so far anyway */
-	// conn.chain = readcertchain("/sys/lib/ssl/vsignss.pem");
-
-	tfd = tlsClient(fd, &conn);
-	close(fd);
-	if(tfd < 0)
-		fprint(2, "%s: tlsClient: %r\n", argv0);
-	else {
-		/* BUG: check cert here? */
-		if(conn.cert)
-			free(conn.cert);
-	}
-	return tfd;
-}
-
-int
-iotlsdial(Ioproc *io, char *addr, char *local, char *dir, int *cfdp,
-	  int usetls)
-{
-	return iocall(io, _iotlsdial, addr, local, dir, cfdp, usetls);
-}

+ 0 - 76
sys/src/cmd/webfs/main.c

@@ -1,76 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ip.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include "dat.h"
-#include "fns.h"
-
-char *cookiefile;
-char *mtpt = "/mnt/web";
-char *service;
-
-Ctl globalctl =
-{
-	1,	/* accept cookies */
-	1,	/* send cookies */
-	10,	/* redirect limit */
-	"webfs/2.0 (plan 9)"	/* user agent */
-};
-
-void
-usage(void)
-{
-	fprint(2, "usage: webfs [-c cookies] [-m mtpt] [-s service]\n");
-	threadexitsall("usage");
-}
-
-#include <pool.h>
-void
-threadmain(int argc, char **argv)
-{
-	rfork(RFNOTEG);
-	ARGBEGIN{
-	case 'd':
-		mainmem->flags |= POOL_PARANOIA|POOL_ANTAGONISM;
-		break;
-	case 'D':
-		chatty9p++;
-		break;
-	case 'c':
-		cookiefile = EARGF(usage());
-		break;
-	case 'm':
-		mtpt = EARGF(usage());
-		break;
-	case 's':
-		service = EARGF(usage());
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	quotefmtinstall();
-	if(argc != 0)
-		usage();
-
-	plumbinit();
-	globalctl.useragent = estrdup(globalctl.useragent);
-	initcookies(cookiefile);
-	initurl();
-	initfs();
-	threadpostmountsrv(&fs, service, mtpt, MREPL);
-	threadexits(nil);
-}

+ 0 - 35
sys/src/cmd/webfs/mkfile

@@ -1,35 +0,0 @@
-</$objtype/mkfile
-BIN=/$objtype/bin
-
-TARG=webfs
-
-SCHEMEOFILES=\
-	file.$O\
-	ftp.$O\
-	http.$O\
-
-OFILES=\
-	buf.$O\
-	client.$O\
-	cookies.$O\
-	fs.$O\
-	http.$O\
-	io.$O\
-	main.$O\
-	plumb.$O\
-	url.$O\
-	util.$O\
-#	$SCHEMEOFILES
-
-HFILES=\
-	dat.h\
-	fns.h\
-
-UPDATE=\
-	mkfile\
-	$HFILES\
-	${OFILES:%.$O=%.c}\
-	${TARG:%=/386/bin/%}\
-
-</sys/src/cmd/mkone
-

+ 0 - 174
sys/src/cmd/webfs/plumb.c

@@ -1,174 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include <thread.h>
-#include <plumb.h>
-#include <9p.h>
-
-#include "dat.h"
-#include "fns.h"
-
-static int		plumbsendfd;
-static int		plumbwebfd;
-static Channel	*plumbchan;
-
-static void	plumbwebproc(void*);
-static void	plumbwebthread(void*);
-static void plumbsendproc(void*);
-
-void
-plumbinit(void)
-{
-	plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
-	plumbwebfd = plumbopen("web", OREAD|OCEXEC);
-}
-
-void
-plumbstart(void)
-{
-	plumbchan = chancreate(sizeof(Plumbmsg*), 0);
-	proccreate(plumbwebproc, nil, STACK);
-	threadcreate(plumbwebthread, nil, STACK);
-}
-
-static void
-plumbwebthread(void*)
-{
-	char *base;
-	Plumbmsg *m;
-
-	for(;;){
-		m = recvp(plumbchan);
-		if(m == nil)
-			threadexits(nil);
-		base = plumblookup(m->attr, "baseurl");
-		if(base == nil)
-			base = m->wdir;
-		plumburl(m->data, base);
-		plumbfree(m);
-	}
-}
-
-static void
-plumbwebproc(void*)
-{
-	Plumbmsg *m;
-
-	for(;;){
-		m = plumbrecv(plumbwebfd);
-		sendp(plumbchan, m);
-		if(m == nil)
-			threadexits(nil);
-	}
-}
-
-static void
-addattr(Plumbmsg *m, char *name, char *value)
-{
-	Plumbattr *a;
-
-	a = malloc(sizeof(Plumbattr));
-	a->name = name;
-	a->value = value;
-	a->next = m->attr;
-	m->attr = a;
-}
-
-static void
-freeattrs(Plumbmsg *m)
-{
-	Plumbattr *a, *next;
-
-	a = m->attr;
-	while(a != nil) {
-		next = a->next;
-		free(a);
-		a = next;
-	}
-}
-
-static struct
-{
-	char	*ctype;
-	char	*ext;
-}
-ctypes[] =
-{
-	{ "application/msword", "doc" },
-	{ "application/pdf", "pdf" },
-	{ "application/postscript", "ps" },
-	{ "application/rtf", "rtf" },
-	{ "image/gif", "gif" },
-	{ "image/jpeg", "jpg" },
-	{ "image/png", "png" },
-	{ "image/ppm", "ppm" },
-	{ "image/tiff", "tiff" },
-	{ "text/html", "html" },
-	{ "text/plain", "txt" },
-	{ "text/xml", "xml" },
-};
-
-void
-replumb(Client *c)
-{
-	int i;
-	Plumbmsg *m;
-	char name[128], *ctype, *ext, *p;
-
-	if(!c->plumbed)
-		return;
-	m = emalloc(sizeof(Plumbmsg));
-	m->src = "webfs";
-	m->dst = nil;
-	m->wdir = "/";
-	m->type = "text";
-	m->attr = nil;
-	addattr(m, "url", c->url->url);
-	ctype = c->contenttype;
-	ext = nil;
-	if(ctype != nil) {
-		addattr(m, "content-type", ctype);
-		for(i = 0; i < nelem(ctypes); i++) {
-			if(strcmp(ctype, ctypes[i].ctype) == 0) {
-				ext = ctypes[i].ext;
-				break;
-			}
-		}
-	}
-	if(ext == nil) {
-		p = strrchr(c->url->url, '/');
-		if(p != nil)
-			p = strrchr(p+1, '.');
-		if(p != nil && strlen(p) <= 5)
-			ext = p+1;
-		else
-			ext = "txt";		/* punt */
-	}
-	c->ext = ext;
-if(0)fprint(2, "content type %s -> extension .%s\n", ctype, ext);
-	m->ndata = snprint(name, sizeof name, "/mnt/web/%d/body.%s", c->num, ext);
-	m->data = estrdup(name);
-	proccreate(plumbsendproc, m, STACK);	/* separate proc to avoid a deadlock */
-}
-
-static void
-plumbsendproc(void *x)
-{
-	Plumbmsg *m;
-
-	m = x;
-	plumbsend(plumbsendfd, m);
-	freeattrs(m);
-	free(m->data);
-	free(m);
-}

+ 0 - 1100
sys/src/cmd/webfs/url.c

@@ -1,1100 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-/*
- * This is a URL parser, written to parse "Common Internet Scheme" URL
- * syntax as described in RFC1738 and updated by RFC2396.  Only absolute URLs
- * are supported, using "server-based" naming authorities in the schemes.
- * Support for literal IPv6 addresses is included, per RFC2732.
- *
- * Current "known" schemes: http, ftp, file.
- *
- * We can do all the parsing operations without Runes since URLs are
- * defined to be composed of US-ASCII printable characters.
- * See RFC1738, RFC2396.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <regexp.h>
-#include <plumb.h>
-#include <thread.h>
-#include <fcall.h>
-#include <9p.h>
-#include "dat.h"
-#include "fns.h"
-
-int urldebug;
-
-/* If set, relative paths with leading ".." segments will have them trimmed */
-#define RemoveExtraRelDotDots	0
-#define ExpandCurrentDocUrls	1
-
-static char*
-schemestrtab[] =
-{
-	nil,
-	"http",
-	"https",
-	"ftp",
-	"file",
-};
-
-static int
-ischeme(char *s)
-{
-	int i;
-
-	for(i=0; i<nelem(schemestrtab); i++)
-		if(schemestrtab[i] && strcmp(s, schemestrtab[i])==0)
-			return i;
-	return USunknown;
-}
-
-/*
- * URI splitting regexp is from RFC2396, Appendix B:
- *		^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
- *		 12            3  4          5       6  7        8 9
- *
- * Example: "http://www.ics.uci.edu/pub/ietf/uri/#Related"
- * $2 = scheme			"http"
- * $4 = authority		"www.ics.uci.edu"
- * $5 = path			"/pub/ietf/uri/"
- * $7 = query			<undefined>
- * $9 = fragment		"Related"
- */
-
-/*
- * RFC2396, Sec 3.1, contains:
- *
- * Scheme names consist of a sequence of characters beginning with a
- * lower case letter and followed by any combination of lower case
- * letters, digits, plus ("+"), period ("."), or hyphen ("-").  For
- * resiliency, programs interpreting URI should treat upper case letters
- * as equivalent to lower case in scheme names (e.g., allow "HTTP" as
- * well as "http").
- */
-
-/*
- * For server-based naming authorities (RFC2396 Sec 3.2.2):
- *    server        = [ [ userinfo "@" ] hostport ]
- *    userinfo      = *( unreserved | escaped |
- *                      ";" | ":" | "&" | "=" | "+" | "$" | "," )
- *    hostport      = host [ ":" port ]
- *    host          = hostname | IPv4address
- *    hostname      = *( domainlabel "." ) toplabel [ "." ]
- *    domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
- *    toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
- *    IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
- *    port          = *digit
- *
- *  The host is a domain name of a network host, or its IPv4 address as a
- *  set of four decimal digit groups separated by ".".  Literal IPv6
- *  addresses are not supported.
- *
- * Note that literal IPv6 address support is outlined in RFC2732:
- *    host          = hostname | IPv4address | IPv6reference
- *    ipv6reference = "[" IPv6address "]"		(RFC2373)
- *
- * Since hostnames and numbers will have to be resolved by the OS anyway,
- * we don't have to parse them too pedantically (counting '.'s, checking
- * for well-formed literal IP addresses, etc.).
- *
- * In FTP/file paths, we reject most ";param"s and querys.  In HTTP paths,
- * we just pass them through.
- *
- * Instead of letting a "path" be 0-or-more characters as RFC2396 suggests,
- * we'll say it's 1-or-more characters, 0-or-1 times.  This way, an absent
- * path yields a nil substring match, instead of an empty one.
- *
- * We're more restrictive than RFC2396 indicates with "userinfo" strings,
- * insisting they have the form "[user[:password]]".  This may need to
- * change at some point, however.
- */
-
-/* RE character-class components -- these go in brackets */
-#define PUNCT			"\\-_.!~*'()"
-#define RES			";/?:@&=+$,"
-#define ALNUM		"a-zA-Z0-9"
-#define HEX			"0-9a-fA-F"
-#define UNRES			ALNUM PUNCT
-
-/* RE components; _N => has N parenthesized subexpressions when expanded */
-#define ESCAPED_1			"(%[" HEX "][" HEX "])"
-#define URIC_2			"([" RES UNRES "]|" ESCAPED_1 ")"
-#define URICNOSLASH_2		"([" UNRES ";?:@&=+$,]|" ESCAPED_1 ")"
-#define USERINFO_2		"([" UNRES ";:&=+$,]|" ESCAPED_1 ")"
-#define PCHAR_2			"([" UNRES ":@&=+$,]|" ESCAPED_1 ")"
-#define PSEGCHAR_3		"([/;]|" PCHAR_2 ")"
-
-typedef struct Retab Retab;
-struct Retab
-{
-	char	*str;
-	Reprog	*prog;
-	int		size;
-	int		ind[5];
-};
-
-enum
-{
-	REsplit = 0,
-	REscheme,
-	REunknowndata,
-	REauthority,
-	REhost,
-	REuserinfo,
-	REabspath,
-	REquery,
-	REfragment,
-	REhttppath,
-	REftppath,
-	REfilepath,
-
-	MaxResub=	20,
-};
-
-Retab retab[] =	/* view in constant width Font */
-{
-[REsplit] =
-	"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]+)?(\\?([^#]*))?(#(.*))?$", nil, 0,
-	/* |-scheme-|      |-auth.-|  |path--|    |query|     |--|frag */
-	{  2,              4,         5,          7,          9},
-
-[REscheme] =
-	"^[a-z][a-z0-9+-.]*$", nil, 0,
-	{ 0, },
-
-[REunknowndata] =
-	"^" URICNOSLASH_2 URIC_2 "*$", nil, 0,
-	{ 0, },
-
-[REauthority] =
-	"^(((" USERINFO_2 "*)@)?(((\\[[^\\]@]+\\])|([^:\\[@]+))(:([0-9]*))?)?)?$", nil, 0,
-	/* |----user info-----|  |--------host----------------|  |-port-| */
-	{  3,                    7,                              11, },
-
-[REhost] =
-	"^(([a-zA-Z0-9\\-.]+)|(\\[([a-fA-F0-9.:]+)\\]))$", nil, 0,
-	/* |--regular host--|     |-IPv6 literal-| */
-	{  2,                     4, },
-
-[REuserinfo] =
-	"^(([^:]*)(:([^:]*))?)$", nil, 0,
-	/* |user-|  |pass-| */
-	{  2,       4, },
-
-[REabspath] =
-	"^/" PSEGCHAR_3 "*$", nil, 0,
-	{ 0, },
-
-[REquery] =
-	"^" URIC_2 "*$", nil, 0,
-	{ 0, },
-
-[REfragment] =
-	"^" URIC_2 "*$", nil, 0,
-	{ 0, },
-
-[REhttppath] =
-	"^.*$", nil, 0,
-	{ 0, },
-
-[REftppath] =
-	"^(.+)(;[tT][yY][pP][eE]=([aAiIdD]))?$", nil, 0,
-	/*|--|-path              |ftptype-| */
-	{ 1,                     3, },
-
-[REfilepath] =
-	"^.*$", nil, 0,
-	{ 0, },
-};
-
-static int
-countleftparen(char *s)
-{
-	int n;
-
-	n = 0;
-	for(; *s; s++)
-		if(*s == '(')
-			n++;
-	return n;
-}
-
-void
-initurl(void)
-{
-	int i, j;
-
-	for(i=0; i<nelem(retab); i++){
-		retab[i].prog = regcomp(retab[i].str);
-		if(retab[i].prog == nil)
-			sysfatal("recomp(%s): %r", retab[i].str);
-		retab[i].size = countleftparen(retab[i].str)+1;
-		for(j=0; j<nelem(retab[i].ind); j++)
-			if(retab[i].ind[j] >= retab[i].size)
-				sysfatal("bad index in regexp table: retab[%d].ind[%d] = %d >= %d",
-					i, j, retab[i].ind[j], retab[i].size);
-		if(MaxResub < retab[i].size)
-			sysfatal("MaxResub too small: %d < %d", MaxResub, retab[i].size);
-	}
-}
-
-typedef struct SplitUrl SplitUrl;
-struct SplitUrl
-{
-	struct {
-		char *s;
-		char *e;
-	} url, scheme, authority, path, query, fragment;
-};
-
-/*
- * Implements the algorithm in RFC2396 sec 5.2 step 6.
- * Returns number of chars written, excluding NUL terminator.
- * dest is known to be >= strlen(base)+rel_len.
- */
-static void
-merge_relative_path(char *base, char *rel_st, int rel_len, char *dest)
-{
-	char *s, *p, *e, *pdest;
-
-	pdest = dest;
-
-	/* 6a: start with base, discard last segment */
-	if(base && base[0]){
-		/* Empty paths don't match in our scheme; 'base' should be nil */
-		assert(base[0] == '/');
-		e = strrchr(base, '/');
-		e++;
-		memmove(pdest, base, e-base);
-		pdest += e-base;
-	}else{
-		/* Artistic license on my part */
-		*pdest++ = '/';
-	}
-
-	/* 6b: append relative component */
-	if(rel_st){
-		memmove(pdest, rel_st, rel_len);
-		pdest += rel_len;
-	}
-
-	/* 6c: remove any occurrences of "./" as a complete segment */
-	s = dest;
-	*pdest = '\0';
-	while(e = strstr(s, "./")){
-		if((e == dest) || (*(e-1) == '/')){
- 			memmove(e, e+2, pdest+1-(e+2));	/* +1 for NUL */
-			pdest -= 2;
-		}else
-			s = e+1;
-	}
-
-	/* 6d: remove a trailing "." as a complete segment */
-	if(pdest>dest && *(pdest-1)=='.' &&
-	  (pdest==dest+1 || *(pdest-2)=='/'))
-		*--pdest = '\0';
-
-	/* 6e: remove occurences of "seg/../", where seg != "..", left->right */
-	s = dest+1;
-	while(e = strstr(s, "/../")){
-		p = e - 1;
-		while(p >= dest && *p != '/')
-			p--;
-		if(memcmp(p, "/../", 4) != 0){
-			memmove(p+1, e+4, pdest+1-(e+4));
-			pdest -= (e+4) - (p+1);
-		}else
-			s = e+1;
-	}
-
-	/* 6f: remove a trailing "seg/..", where seg isn't ".."  */
-	if(pdest-3 > dest && memcmp(pdest-3, "/..", 3)==0){
-		p = pdest-3 - 1;
-		while(p >= dest && *p != '/')
-			p--;
-		if(memcmp(p, "/../", 4) != 0){
-			pdest = p+1;
-			*pdest = '\0';
-		}
-	}
-
-	/* 6g: leading ".." segments are errors -- we'll just blat them out. */
-	if(RemoveExtraRelDotDots){
-		p = dest;
-		if (p[0] == '/')
-			p++;
-		s = p;
-		while(s[0]=='.' && s[1]=='.' && (s[2]==0 || s[2]=='/'))
-			s += 3;
-		if(s > p){
-			memmove(p, s, pdest+1-s);
-			pdest -= s-p;
-		}
-	}
-	USED(pdest);
-
-	if(urldebug)
-		fprint(2, "merge_relative_path: '%s' + '%.*s' -> '%s'\n", base, rel_len,
-			rel_st, dest);
-}
-
-/*
- * See RFC2396 sec 5.2 for info on resolving relative URIs to absolute form.
- *
- * If successful, this just ends up freeing and replacing "u->url".
- */
-static int
-resolve_relative(SplitUrl *su, Url *base, Url *u)
-{
-	char *url, *path;
-	char *purl, *ppath;
-	int currentdoc, ulen, plen;
-
-	if(base == nil){
-		werrstr("relative URI given without base");
-		return -1;
-	}
-	if(base->scheme == nil){
-		werrstr("relative URI given with no scheme");
-		return -1;
-	}
-	if(base->ischeme == USunknown){
-		werrstr("relative URI given with unknown scheme");
-		return -1;
-	}
-	if(base->ischeme == UScurrent){
-		werrstr("relative URI given with incomplete base");
-		return -1;
-	}
-	assert(su->scheme.s == nil);
-
-	/* Sec 5.2 step 2 */
-	currentdoc = 0;
-	if(su->path.s==nil && su->scheme.s==nil && su->authority.s==nil && su->query.s==nil){
-		/* Reference is to current document */
-		if(urldebug)
-			fprint(2, "url %s is relative to current document\n", u->url);
-		u->ischeme = UScurrent;
-		if(!ExpandCurrentDocUrls)
-			return 0;
-		currentdoc = 1;
-	}
-
-	/* Over-estimate the maximum lengths, for allocation purposes */
-	/* (constants are for separators) */
-	plen = 1;
-	if(base->path)
-		plen += strlen(base->path);
-	if(su->path.s)
-		plen += 1 + (su->path.e - su->path.s);
-
-	ulen = 0;
-	ulen += strlen(base->scheme) + 1;
-	if(su->authority.s)
-		ulen += 2 + (su->authority.e - su->authority.s);
-	else
-		ulen += 2 + ((base->authority) ? strlen(base->authority) : 0);
-	ulen += plen;
-	if(su->query.s)
-		ulen += 1 + (su->query.e - su->query.s);
-	else if(currentdoc && base->query)
-		ulen += 1 + strlen(base->query);
-	if(su->fragment.s)
-		ulen += 1 + (su->fragment.e - su->fragment.s);
-	else if(currentdoc && base->fragment)
-		ulen += 1 + strlen(base->fragment);
-	url = emalloc(ulen+1);
-	path = emalloc(plen+1);
-
-	url[0] = '\0';
-	purl = url;
-	path[0] = '\0';
-	ppath = path;
-
-	if(su->authority.s || (su->path.s && (su->path.s[0] == '/'))){
-		/* Is a "network-path" or "absolute-path"; don't merge with base path */
-		/* Sec 5.2 steps 4,5 */
-		if(su->path.s){
-			memmove(ppath, su->path.s, su->path.e - su->path.s);
-			ppath += su->path.e - su->path.s;
-			*ppath = '\0';
-		}
-	}else if(currentdoc){
-		/* Is a current-doc reference; just copy the path from the base URL */
-		if(base->path){
-			strcpy(ppath, base->path);
-			ppath += strlen(ppath);
-		}
-		USED(ppath);
-	}else{
-		/* Is a relative-path reference; we have to merge it */
-		/* Sec 5.2 step 6 */
-		merge_relative_path(base->path,
-			su->path.s, su->path.e - su->path.s, ppath);
-	}
-
-	/* Build new URL from pieces, inheriting from base where needed */
-	strcpy(purl, base->scheme);
-	purl += strlen(purl);
-	*purl++ = ':';
-	if(su->authority.s){
-		strcpy(purl, "//");
-		purl += strlen(purl);
-		memmove(purl, su->authority.s, su->authority.e - su->authority.s);
-		purl += su->authority.e - su->authority.s;
-	}else if(base->authority){
-		strcpy(purl, "//");
-		purl += strlen(purl);
-		strcpy(purl, base->authority);
-		purl += strlen(purl);
-	}
-	assert((path[0] == '\0') || (path[0] == '/'));
-	strcpy(purl, path);
-	purl += strlen(purl);
-
-	/*
-	 * The query and fragment are not inherited from the base,
-	 * except in case of "current document" URLs, which inherit any query
-	 * and may inherit the fragment.
-	 */
-	if(su->query.s){
-		*purl++ = '?';
-		memmove(purl, su->query.s, su->query.e - su->query.s);
-		purl += su->query.e - su->query.s;
-	}else if(currentdoc && base->query){
-		*purl++ = '?';
-		strcpy(purl, base->query);
-		purl += strlen(purl);
-	}
-
-	if(su->fragment.s){
-		*purl++ = '#';
-		memmove(purl, su->query.s, su->query.e - su->query.s);
-		purl += su->fragment.e - su->fragment.s;
-	}else if(currentdoc && base->fragment){
-		*purl++ = '#';
-		strcpy(purl, base->fragment);
-		purl += strlen(purl);
-	}
-	USED(purl);
-
-	if(urldebug)
-		fprint(2, "resolve_relative: '%s' + '%s' -> '%s'\n", base->url, u->url, url);
-	free(u->url);
-	u->url = url;
-	free(path);
-	return 0;
-}
-
-int
-regx(Reprog *prog, char *s, Resub *m, int nm)
-{
-	int i;
-
-	if(s == nil)
-		s = m[0].sp;	/* why is this necessary? */
-
-	i = regexec(prog, s, m, nm);
-/*
-	if(i >= 0)
-		for(j=0; j<nm; j++)
-			fprint(2, "match%d: %.*s\n", j, utfnlen(m[j].sp, m[j].ep-m[j].sp), m[j].sp);
-*/
-	return i;
-}
-
-static int
-ismatch(int i, char *s, char *desc)
-{
-	Resub m[1];
-
-	m[0].sp = m[0].ep = nil;
-	if(!regx(retab[i].prog, s, m, 1)){
-		werrstr("malformed %s: %q", desc, s);
-		return 0;
-	}
-	return 1;
-}
-
-static int
-spliturl(char *url, SplitUrl *su)
-{
-	Resub m[MaxResub];
-	Retab *t;
-
-	/*
-	 * Newlines are not valid in a URI, but regexp(2) treats them specially
-	 * so it's best to make sure there are none before proceeding.
-	 */
-	if(strchr(url, '\n')){
-		werrstr("newline in URI");
-		return -1;
-	}
-
-	/*
-	 * Because we use NUL-terminated strings, as do many client and server
-	 * implementations, an escaped NUL ("%00") will quite likely cause problems
-	 * when unescaped.  We can check for such a sequence once before examining
- 	 * the components because, per RFC2396 sec. 2.4.1 - 2.4.2, '%' is reserved
-	 * in URIs to _always_ indicate escape sequences.  Something like "%2500"
-	 * will still get by, but that's legitimate, and if it ends up causing
-	 * a NUL then someone is unescaping too many times.
-	 */
-	if(strstr(url, "%00")){
-		werrstr("escaped NUL in URI");
-		return -1;
-	}
-
-	m[0].sp = m[0].ep = nil;
-	t = &retab[REsplit];
-	if(!regx(t->prog, url, m, t->size)){
-		werrstr("malformed URI: %q", url);
-		return -1;
-	}
-
-	su->url.s = m[0].sp;
-	su->url.e = m[0].ep;
-	su->scheme.s = m[t->ind[0]].sp;
-	su->scheme.e = m[t->ind[0]].ep;
-	su->authority.s = m[t->ind[1]].sp;
-	su->authority.e = m[t->ind[1]].ep;
-	su->path.s = m[t->ind[2]].sp;
-	su->path.e = m[t->ind[2]].ep;
-	su->query.s = m[t->ind[3]].sp;
-	su->query.e = m[t->ind[3]].ep;
-	su->fragment.s = m[t->ind[4]].sp;
-	su->fragment.e = m[t->ind[4]].ep;
-
-	if(urldebug)
-		fprint(2, "split url %s into %.*q %.*q %.*q %.*q %.*q %.*q\n",
-			url,
-			su->url.s ? utfnlen(su->url.s, su->url.e-su->url.s) : 10, su->url.s ? su->url.s : "",
-			su->scheme.s ? utfnlen(su->scheme.s, su->scheme.e-su->scheme.s) : 10, su->scheme.s ? su->scheme.s : "",
-			su->authority.s ? utfnlen(su->authority.s, su->authority.e-su->authority.s) : 10, su->authority.s ? su->authority.s : "",
-			su->path.s ? utfnlen(su->path.s, su->path.e-su->path.s) : 10, su->path.s ? su->path.s : "",
-			su->query.s ? utfnlen(su->query.s, su->query.e-su->query.s) : 10, su->query.s ? su->query.s : "",
-			su->fragment.s ? utfnlen(su->fragment.s, su->fragment.e-su->fragment.s) : 10, su->fragment.s ? su->fragment.s : "");
-
-	return 0;
-}
-
-static int
-parse_scheme(SplitUrl *su, Url *u)
-{
-	if(su->scheme.s == nil){
-		werrstr("missing scheme");
-		return -1;
-	}
-	u->scheme = estredup(su->scheme.s, su->scheme.e);
-	strlower(u->scheme);
-
-	if(!ismatch(REscheme, u->scheme, "scheme"))
-		return -1;
-
-	u->ischeme = ischeme(u->scheme);
-	if(urldebug)
-		fprint(2, "parse_scheme %s => %d\n", u->scheme, u->ischeme);
-	return 0;
-}
-
-static int
-parse_unknown_part(SplitUrl *su, Url *u)
-{
-	char *s, *e;
-
-	assert(u->ischeme == USunknown);
-	assert(su->scheme.e[0] == ':');
-
-	s = su->scheme.e+1;
-	if(su->fragment.s){
-		e = su->fragment.s-1;
-		assert(*e == '#');
-	}else
-		e = s+strlen(s);
-
-	u->schemedata = estredup(s, e);
-	if(!ismatch(REunknowndata, u->schemedata, "unknown scheme data"))
-		return -1;
-	return 0;
-}
-
-static int
-parse_userinfo(char *s, char *e, Url *u)
-{
-	Resub m[MaxResub];
-	Retab *t;
-
-	m[0].sp = s;
-	m[0].ep = e;
-	t = &retab[REuserinfo];
-	if(!regx(t->prog, nil, m, t->size)){
-		werrstr("malformed userinfo: %.*q", utfnlen(s, e-s), s);
-		return -1;
-	}
-	if(m[t->ind[0]].sp)
-		u->user = estredup(m[t->ind[0]].sp, m[t->ind[0]].ep);
-	if(m[t->ind[1]].sp)
-		u->user = estredup(m[t->ind[1]].sp, m[t->ind[1]].ep);
-	return 0;
-}
-
-static int
-parse_host(char *s, char *e, Url *u)
-{
-	Resub m[MaxResub];
-	Retab *t;
-
-	m[0].sp = s;
-	m[0].ep = e;
-	t = &retab[REhost];
-	if(!regx(t->prog, nil, m, t->size)){
-		werrstr("malformed host: %.*q", utfnlen(s, e-s), s);
-		return -1;
-	}
-
-	assert(m[t->ind[0]].sp || m[t->ind[1]].sp);
-
-	if(m[t->ind[0]].sp)	/* regular */
-		u->host = estredup(m[t->ind[0]].sp, m[t->ind[0]].ep);
-	else
-		u->host = estredup(m[t->ind[1]].sp, m[t->ind[1]].ep);
-	return 0;
-}
-
-static int
-parse_authority(SplitUrl *su, Url *u)
-{
-	Resub m[MaxResub];
-	Retab *t;
-	char *host;
-	char *userinfo;
-
-	if(su->authority.s == nil)
-		return 0;
-
-	u->authority = estredup(su->authority.s, su->authority.e);
-	m[0].sp = m[0].ep = nil;
-	t = &retab[REauthority];
-	if(!regx(t->prog, u->authority, m, t->size)){
-		werrstr("malformed authority: %q", u->authority);
-		return -1;
-	}
-
-	if(m[t->ind[0]].sp)
-		if(parse_userinfo(m[t->ind[0]].sp, m[t->ind[0]].ep, u) < 0)
-			return -1;
-	if(m[t->ind[1]].sp)
-		if(parse_host(m[t->ind[1]].sp, m[t->ind[1]].ep, u) < 0)
-			return -1;
-	if(m[t->ind[2]].sp)
-		u->port = estredup(m[t->ind[2]].sp, m[t->ind[2]].ep);
-
-
-	if(urldebug > 0){
-		userinfo = estredup(m[t->ind[0]].sp, m[t->ind[0]].ep);
-		host = estredup(m[t->ind[1]].sp, m[t->ind[1]].ep);
-		fprint(2, "port: %q, authority %q\n", u->port, u->authority);
-		fprint(2, "host %q, userinfo %q\n", host, userinfo);
-		free(host);
-		free(userinfo);
-	}
-	return 0;
-}
-
-static int
-parse_abspath(SplitUrl *su, Url *u)
-{
-	if(su->path.s == nil)
-		return 0;
-	u->path = estredup(su->path.s, su->path.e);
-	if(!ismatch(REabspath, u->path, "absolute path"))
-		return -1;
-	return 0;
-}
-
-static int
-parse_query(SplitUrl *su, Url *u)
-{
-	if(su->query.s == nil)
-		return 0;
-	u->query = estredup(su->query.s, su->query.e);
-	if(!ismatch(REquery, u->query, "query"))
-		return -1;
-	return 0;
-}
-
-static int
-parse_fragment(SplitUrl *su, Url *u)
-{
-	if(su->fragment.s == nil)
-		return 0;
-	u->fragment = estredup(su->fragment.s, su->fragment.e);
-	if(!ismatch(REfragment, u->fragment, "fragment"))
-		return -1;
-	return 0;
-}
-
-static int
-postparse_http(Url *u)
-{
-	u->open = httpopen;
-	u->read = httpread;
-	u->close = httpclose;
-
-	if(u->authority==nil){
-		werrstr("missing authority (hostname, port, etc.)");
-		return -1;
-	}
-	if(u->host == nil){
-		werrstr("missing host specification");
-		return -1;
-	}
-
-	if(u->path == nil){
-		u->http.page_spec = estrdup("/");
-		return 0;
-	}
-
-	if(!ismatch(REhttppath, u->path, "http path"))
-		return -1;
-	if(u->query){
-		u->http.page_spec = emalloc(strlen(u->path)+1+strlen(u->query)+1);
-		strcpy(u->http.page_spec, u->path);
-		strcat(u->http.page_spec, "?");
-		strcat(u->http.page_spec, u->query);
-	}else
-		u->http.page_spec = estrdup(u->path);
-
-	return 0;
-}
-
-static int
-postparse_ftp(Url *u)
-{
-	Resub m[MaxResub];
-	Retab *t;
-
-	if(u->authority==nil){
-		werrstr("missing authority (hostname, port, etc.)");
-		return -1;
-	}
-	if(u->query){
-		werrstr("unexpected \"?query\" in ftp path");
-		return -1;
-	}
-	if(u->host == nil){
-		werrstr("missing host specification");
-		return -1;
-	}
-
-	if(u->path == nil){
-		u->ftp.path_spec = estrdup("/");
-		return 0;
-	}
-
-	m[0].sp = m[0].ep = nil;
-	t = &retab[REftppath];
-	if(!regx(t->prog, u->path, m, t->size)){
-		werrstr("malformed ftp path: %q", u->path);
-		return -1;
-	}
-
-	if(m[t->ind[0]].sp){
-		u->ftp.path_spec = estredup(m[t->ind[0]].sp, m[t->ind[0]].ep);
-		if(strchr(u->ftp.path_spec, ';')){
-			werrstr("unexpected \";param\" in ftp path");
-			return -1;
-		}
-	}else
-		u->ftp.path_spec = estrdup("/");
-
-	if(m[t->ind[1]].sp){
-		u->ftp.type = estredup(m[t->ind[1]].sp, m[t->ind[1]].ep);
-		strlower(u->ftp.type);
-	}
-	return 0;
-}
-
-static int
-postparse_file(Url *u)
-{
-	if(u->user || u->passwd){
-		werrstr("user information not valid with file scheme");
-		return -1;
-	}
-	if(u->query){
-		werrstr("unexpected \"?query\" in file path");
-		return -1;
-	}
-	if(u->port){
-		werrstr("port not valid with file scheme");
-		return -1;
-	}
-	if(u->path == nil){
-		werrstr("missing path in file scheme");
-		return -1;
-	}
-	if(strchr(u->path, ';')){
-		werrstr("unexpected \";param\" in file path");
-		return -1;
-	}
-
-	if(!ismatch(REfilepath, u->path, "file path"))
-		return -1;
-
-	/* "localhost" is equivalent to no host spec, we'll chose the latter */
-	if(u->host && cistrcmp(u->host, "localhost") == 0){
-		free(u->host);
-		u->host = nil;
-	}
-	return 0;
-}
-
-static int (*postparse[])(Url*) = {
-	nil,
-	postparse_http,
-	postparse_http,
-	postparse_ftp,
-	postparse_file,
-};
-
-Url*
-parseurl(char *url, Url *base)
-{
-	Url *u;
-	SplitUrl su;
-
-	if(urldebug)
-		fprint(2, "parseurl %s with base %s\n", url, base ? base->url : "<none>");
-
-	u = emalloc(sizeof(Url));
-	u->url = estrdup(url);
-	if(spliturl(u->url, &su) < 0){
-	Fail:
-		freeurl(u);
-		return nil;
-	}
-
-	/* RFC2396 sec 3.1 says relative URIs are distinguished by absent scheme */
-	if(su.scheme.s==nil){
-		if(urldebug)
-			fprint(2, "parseurl has nil scheme\n");
-		if(resolve_relative(&su, base, u) < 0 || spliturl(u->url, &su) < 0)
-			goto Fail;
-		if(u->ischeme == UScurrent){
-			/* 'u.url' refers to current document; set fragment and return */
-			if(parse_fragment(&su, u) < 0)
-				goto Fail;
-			return u;
-		}
-	}
-
-	if(parse_scheme(&su, u) < 0
-	|| parse_fragment(&su, u) < 0)
-		goto Fail;
-
-	if(u->ischeme == USunknown){
-		if(parse_unknown_part(&su, u) < 0)
-			goto Fail;
-		return u;
-	}
-
-	if(parse_query(&su, u) < 0
-	|| parse_authority(&su, u) < 0
-	|| parse_abspath(&su, u) < 0)
-		goto Fail;
-
-	if(u->ischeme < nelem(postparse) && postparse[u->ischeme])
-		if((*postparse[u->ischeme])(u) < 0)
-			goto Fail;
-
-	setmalloctag(u, getcallerpc(&url));
-	return u;
-}
-
-void
-freeurl(Url *u)
-{
-	if(u == nil)
-		return;
-	free(u->url);
-	free(u->scheme);
-	free(u->schemedata);
-	free(u->authority);
-	free(u->user);
-	free(u->passwd);
-	free(u->host);
-	free(u->port);
-	free(u->path);
-	free(u->query);
-	free(u->fragment);
-	switch(u->ischeme){
-	case UShttp:
-		free(u->http.page_spec);
-		break;
-	case USftp:
-		free(u->ftp.path_spec);
-		free(u->ftp.type);
-		break;
-	}
-	free(u);
-}
-
-void
-rewriteurl(Url *u)
-{
-	char *s;
-
-	if(u->schemedata)
-		s = estrmanydup(u->scheme, ":", u->schemedata, nil);
-	else
-		s = estrmanydup(u->scheme, "://",
-			u->user ? u->user : "",
-			u->passwd ? ":" : "", u->passwd ? u->passwd : "",
-			u->user ? "@" : "", u->host ? u->host : "",
-			u->port ? ":" : "", u->port ? u->port : "",
-			u->path,
-			u->query ? "?" : "", u->query ? u->query : "",
-			u->fragment ? "#" : "", u->fragment ? u->fragment : "",
-			nil);
-	free(u->url);
-	u->url = s;
-}
-
-int
-seturlquery(Url *u, char *query)
-{
-	if(query == nil){
-		free(u->query);
-		u->query = nil;
-		return 0;
-	}
-
-	if(!ismatch(REquery, query, "query"))
-		return -1;
-
-	free(u->query);
-	u->query = estrdup(query);
-	return 0;
-}
-
-static void
-dupp(char **p)
-{
-	if(*p)
-		*p = estrdup(*p);
-}
-
-Url*
-copyurl(Url *u)
-{
-	Url *v;
-
-	v = emalloc(sizeof(Url));
-	*v = *u;
-	dupp(&v->url);
-	dupp(&v->scheme);
-	dupp(&v->schemedata);
-	dupp(&v->authority);
-	dupp(&v->user);
-	dupp(&v->passwd);
-	dupp(&v->host);
-	dupp(&v->port);
-	dupp(&v->path);
-	dupp(&v->query);
-	dupp(&v->fragment);
-
-	switch(v->ischeme){
-	case UShttp:
-		dupp(&v->http.page_spec);
-		break;
-	case USftp:
-		dupp(&v->ftp.path_spec);
-		dupp(&v->ftp.type);
-		break;
-	}
-	return v;
-}
-
-static int
-dhex(char c)
-{
-	if('0' <= c && c <= '9')
-		return c-'0';
-	if('a' <= c && c <= 'f')
-		return c-'a'+10;
-	if('A' <= c && c <= 'F')
-		return c-'A'+10;
-	return 0;
-}
-
-char*
-escapeurl(char *s, int (*needesc)(int))
-{
-	int n;
-	char *t, *u;
-	Rune r;
-	static char *hex = "0123456789abcdef";
-
-	n = 0;
-	for(t=s; *t; t++)
-		if((*needesc)(*t))
-			n++;
-
-	u = emalloc(strlen(s)+2*n+1);
-	t = u;
-	for(; *s; s++){
-		s += chartorune(&r, s);
-		if(r >= 0xFF){
-			werrstr("URLs cannot contain Runes > 0xFF");
-			free(t);
-			return nil;
-		}
-		if((*needesc)(r)){
-			*u++ = '%';
-			*u++ = hex[(r>>4)&0xF];
-			*u++ = hex[r&0xF];
-		}else
-			*u++ = r;
-	}
-	*u = '\0';
-	return t;
-}
-
-char*
-unescapeurl(char *s)
-{
-	char *r, *w;
-	Rune rune;
-
-	s = estrdup(s);
-	for(r=w=s; *r; r++){
-		if(*r=='%'){
-			r++;
-			if(!isxdigit(r[0]) || !isxdigit(r[1])){
-				werrstr("bad escape sequence '%.3s' in URL", r);
-				return nil;
-			}
-			if(r[0]=='0' && r[2]=='0'){
-				werrstr("escaped NUL in URL");
-				return nil;
-			}
-			rune = (dhex(r[0])<<4)|dhex(r[1]);	/* latin1 */
-			w += runetochar(w, &rune);
-			r += 2;
-		}else
-			*w++ = *r;
-	}
-	*w = '\0';
-	return s;
-}

+ 0 - 95
sys/src/cmd/webfs/util.c

@@ -1,95 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <ndb.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-#include <ctype.h>
-#include "dat.h"
-#include "fns.h"
-
-void*
-erealloc(void *a, uint n)
-{
-	a = realloc(a, n);
-	if(a == nil)
-		sysfatal("realloc %d: out of memory", n);
-	setrealloctag(a, getcallerpc(&a));
-	return a;
-}
-
-void*
-emalloc(uint n)
-{
-	void *a;
-
-	a = mallocz(n, 1);
-	if(a == nil)
-		sysfatal("malloc %d: out of memory", n);
-	setmalloctag(a, getcallerpc(&n));
-	return a;
-}
-
-char*
-estrdup(char *s)
-{
-	s = strdup(s);
-	if(s == nil)
-		sysfatal("strdup: out of memory");
-	setmalloctag(s, getcallerpc(&s));
-	return s;
-}
-
-char*
-estredup(char *s, char *e)
-{
-	char *t;
-
-	t = emalloc(e-s+1);
-	memmove(t, s, e-s);
-	t[e-s] = '\0';
-	setmalloctag(t, getcallerpc(&s));
-	return t;
-}
-
-char*
-estrmanydup(char *s, ...)
-{
-	char *p, *t;
-	int len;
-	va_list arg;
-
-	len = strlen(s);
-	va_start(arg, s);
-	while((p = va_arg(arg, char*)) != nil)
-		len += strlen(p);
-	len++;
-
-	t = emalloc(len);
-	strcpy(t, s);
-	va_start(arg, s);
-	while((p = va_arg(arg, char*)) != nil)
-		strcat(t, p);
-	return t;
-}
-
-char*
-strlower(char *s)
-{
-	char *t;
-
-	for(t=s; *t; t++)
-		if('A' <= *t && *t <= 'Z')
-			*t += 'a'-'A';
-	return s;
-}

+ 0 - 96
sys/src/cmd/webfs/webget.c

@@ -1,96 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-/*
- * Sample client.
- */
-#include <u.h>
-#include <libc.h>
-
-void
-xfer(int from, int to)
-{
-	char buf[12*1024];
-	int n;
-
-	while((n = read(from, buf, sizeof buf)) > 0)
-		if(write(to, buf, n) < 0)
-			sysfatal("write failed: %r");
-	if(n < 0)
-		sysfatal("read failed: %r");
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: webget [-b baseurl] [-m mtpt] [-p postbody] url\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	int conn, ctlfd, fd, n;
-	char buf[128], *base, *mtpt, *post, *url;
-
-	mtpt = "/mnt/web";
-	post = nil;
-	base = nil;
-	ARGBEGIN{
-	default:
-		usage();
-	case 'b':
-		base = EARGF(usage());
-		break;
-	case 'm':
-		mtpt = EARGF(usage());
-		break;
-	case 'p':
-		post = EARGF(usage());
-		break;
-	}ARGEND;
-
-	if (argc != 1)
-		usage();
-
-	url = argv[0];
-
-	snprint(buf, sizeof buf, "%s/clone", mtpt);
-	if((ctlfd = open(buf, ORDWR)) < 0)
-		sysfatal("couldn't open %s: %r", buf);
-	if((n = read(ctlfd, buf, sizeof buf-1)) < 0)
-		sysfatal("reading clone: %r");
-	if(n == 0)
-		sysfatal("short read on clone");
-	buf[n] = '\0';
-	conn = atoi(buf);
-
-	if(base)
-		if(fprint(ctlfd, "baseurl %s", base) < 0)
-			sysfatal("baseurl ctl write: %r");
-
-	if(fprint(ctlfd, "url %s", url) <= 0)
-		sysfatal("get ctl write: %r");
-
-	if(post){
-		snprint(buf, sizeof buf, "%s/%d/postbody", mtpt, conn);
-		if((fd = open(buf, OWRITE)) < 0)
-			sysfatal("open %s: %r", buf);
-		if(write(fd, post, strlen(post)) < 0)
-			sysfatal("post write failed: %r");
-		close(fd);
-	}
-
-	snprint(buf, sizeof buf, "%s/%d/body", mtpt, conn);
-	if((fd = open(buf, OREAD)) < 0)
-		sysfatal("open %s: %r", buf);
-
-	xfer(fd, 1);
-	exits(nil);
-}

+ 0 - 889
sys/src/cmd/wikifs/fs.c

@@ -1,889 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-#include <auth.h>
-#include <fcall.h>
-#include <9p.h>
-
-enum {
-	Qindexhtml,
-	Qindextxt,
-	Qraw,
-	Qhistoryhtml,
-	Qhistorytxt,
-	Qdiffhtml,
-	Qedithtml,
-	Qwerrorhtml,
-	Qwerrortxt,
-	Qhttplogin,
-	Nfile,
-};
-
-static char *filelist[] = {
-	"index.html",
-	"index.txt",
-	"current",
-	"history.html",
-	"history.txt",
-	"diff.html",
-	"edit.html",
-	"werror.html",
-	"werror.txt",
-	".httplogin",
-};
-
-static int needhist[Nfile] = {
-[Qhistoryhtml] 1,
-[Qhistorytxt] 1,
-[Qdiffhtml] 1,
-};
-
-/*
- * The qids are <8-bit type><16-bit page number><16-bit page version><8-bit file index>.
- */
-enum {		/* <8-bit type> */
-	Droot = 1,
-	D1st,
-	D2nd,
-	Fnew,
-	Fmap,
-	F1st,
-	F2nd,
-};
-
-uint64_t
-mkqid(int type, int num, int vers, int file)
-{
-	return ((uint64_t)type<<40) | ((uint64_t)num<<24) | (vers<<8) | file;
-}
-
-int
-qidtype(uint64_t path)
-{
-	return (path>>40)&0xFF;
-}
-
-int
-qidnum(uint64_t path)
-{
-	return (path>>24)&0xFFFF;
-}
-
-int
-qidvers(uint64_t path)
-{
-	return (path>>8)&0xFFFF;
-}
-
-int
-qidfile(uint64_t path)
-{
-	return path&0xFF;
-}
-
-typedef struct Aux Aux;
-struct Aux {
-	String *name;
-	Whist *w;
-	int n;
-	uint32_t t;
-	String *s;
-	Map *map;
-};
-
-static void
-fsattach(Req *r)
-{
-	Aux *a;
-
-	if(r->ifcall.aname && r->ifcall.aname[0]){
-		respond(r, "invalid attach specifier");
-		return;
-	}
-
-	a = emalloc(sizeof(Aux));
-	r->fid->aux = a;
-	a->name = s_copy(r->ifcall.uname);
-
-	r->ofcall.qid = (Qid){mkqid(Droot, 0, 0, 0), 0, QTDIR};
-	r->fid->qid = r->ofcall.qid;
-	respond(r, nil);
-}
-
-static String *
-httplogin(void)
-{
-	String *s=s_new();
-	Biobuf *b;
-
-	if((b = wBopen(".httplogin", OREAD)) == nil)
-		goto Return;
-
-	while(s_read(b, s, Bsize) > 0)
-		;
-	Bterm(b);
-
-Return:
-	return s;
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{
-	char *q;
-	int i, isdotdot, n, t;
-	uint64_t path;
-	Aux *a;
-	Whist *wh;
-	String *s;
-
-	isdotdot = strcmp(name, "..")==0;
-	n = strtoul(name, &q, 10);
-	path = fid->qid.path;
-	a = fid->aux;
-
-	switch(qidtype(path)){
-	case 0:
-		return "wikifs: bad path in server (bug)";
-
-	case Droot:
-		if(isdotdot){
-			*qid = fid->qid;
-			return nil;
-		}
-		if(strcmp(name, "new")==0){
-			*qid = (Qid){mkqid(Fnew, 0, 0, 0), 0, 0};
-			return nil;
-		}
-		if(strcmp(name, "map")==0){
-			*qid = (Qid){mkqid(Fmap, 0, 0, 0), 0, 0};
-			return nil;
-		}
-		if((*q!='\0' || (wh=getcurrent(n))==nil)
-		&& (wh=getcurrentbyname(name))==nil)
-			return "file does not exist";
-		*qid = (Qid){mkqid(D1st, wh->n, 0, 0), wh->doc->time, QTDIR};
-		a->w = wh;
-		return nil;
-
-	case D1st:
-		if(isdotdot){
-			*qid = (Qid){mkqid(Droot, 0, 0, 0), 0, QTDIR};
-			return nil;
-		}
-
-		/* handle history directories */
-		if(*q == '\0'){
-			if((wh = gethistory(qidnum(path))) == nil)
-				return "file does not exist";
-			for(i=0; i<wh->ndoc; i++)
-				if(wh->doc[i].time == n)
-					break;
-			if(i==wh->ndoc){
-				closewhist(wh);
-				return "file does not exist";
-			}
-			closewhist(a->w);
-			a->w = wh;
-			a->n = i;
-			*qid = (Qid){mkqid(D2nd, qidnum(path), i, 0), wh->doc[i].time, QTDIR};
-			return nil;
-		}
-
-		/* handle files other than index */
-		for(i=0; i<nelem(filelist); i++){
-			if(strcmp(name, filelist[i])==0){
-				if(needhist[i]){
-					if((wh = gethistory(qidnum(path))) == nil)
-						return "file does not exist";
-					closewhist(a->w);
-					a->w = wh;
-				}
-				*qid = (Qid){mkqid(F1st, qidnum(path), 0, i), a->w->doc->time, 0};
-				goto Gotfile;
-			}
-		}
-		return "file does not exist";
-
-	case D2nd:
-		if(isdotdot){
-			/*
-			 * Can't use a->w[a->ndoc-1] because that
-			 * might be a failed write rather than the real one.
-			 */
-			*qid = (Qid){mkqid(D1st, qidnum(path), 0, 0), 0, QTDIR};
-			if((wh = getcurrent(qidnum(path))) == nil)
-				return "file does not exist";
-			closewhist(a->w);
-			a->w = wh;
-			a->n = 0;
-			return nil;
-		}
-		for(i=0; i<=Qraw; i++){
-			if(strcmp(name, filelist[i])==0){
-				*qid = (Qid){mkqid(F2nd, qidnum(path), qidvers(path), i), a->w->doc->time, 0};
-				goto Gotfile;
-			}
-		}
-		return "file does not exist";
-
-	default:
-		return "bad programming";
-	}
-	/* not reached */
-
-Gotfile:
-	t = qidtype(qid->path);
-	switch(qidfile(qid->path)){
-	case Qindexhtml:
-		s = tohtml(a->w, a->w->doc+a->n,
-			t==F1st? Tpage : Toldpage);
-		break;
-	case Qindextxt:
-		s = totext(a->w, a->w->doc+a->n,
-			t==F1st? Tpage : Toldpage);
-		break;
-	case Qraw:
-		s = s_copy(a->w->title);
-		s = s_append(s, "\n");
-		s = doctext(s, &a->w->doc[a->n]);
-		break;
-	case Qhistoryhtml:
-		s = tohtml(a->w, a->w->doc+a->n, Thistory);
-		break;
-	case Qhistorytxt:
-		s = totext(a->w, a->w->doc+a->n, Thistory);
-		break;
-	case Qdiffhtml:
-		s = tohtml(a->w, a->w->doc+a->n, Tdiff);
-		break;
-	case Qedithtml:
-		s = tohtml(a->w, a->w->doc+a->n, Tedit);
-		break;
-	case Qwerrorhtml:
-		s = tohtml(a->w, a->w->doc+a->n, Twerror);
-		break;
-	case Qwerrortxt:
-		s = totext(a->w, a->w->doc+a->n, Twerror);
-		break;
-	case Qhttplogin:
-		s = httplogin();
-		break;
-	default:
-		return "internal error";
-	}
-	a->s = s;
-	return nil;
-}
-
-static void
-fsopen(Req *r)
-{
-	int t;
-	uint64_t path;
-	Aux *a;
-	Fid *fid;
-	Whist *wh;
-
-	fid = r->fid;
-	path = fid->qid.path;
-	t = qidtype(fid->qid.path);
-	if((r->ifcall.mode != OREAD && t != Fnew && t != Fmap)
-	|| (r->ifcall.mode&ORCLOSE)){
-		respond(r, "permission denied");
-		return;
-	}
-
-	a = fid->aux;
-	switch(t){
-	case Droot:
-		currentmap(0);
-		rlock(&maplock);
-		a->map = map;
-		incref(map);
-		runlock(&maplock);
-		respond(r, nil);
-		break;
-
-	case D1st:
-		if((wh = gethistory(qidnum(path))) == nil){
-			respond(r, "file does not exist");
-			return;
-		}
-		closewhist(a->w);
-		a->w = wh;
-		a->n = a->w->ndoc-1;
-		r->ofcall.qid.vers = wh->doc[a->n].time;
-		r->fid->qid = r->ofcall.qid;
-		respond(r, nil);
-		break;
-
-	case D2nd:
-		respond(r, nil);
-		break;
-
-	case Fnew:
-		a->s = s_copy("");
-		respond(r, nil);
-		break;
-
-	case Fmap:
-	case F1st:
-	case F2nd:
-		respond(r, nil);
-		break;
-
-	default:
-		respond(r, "programmer error");
-		break;
-	}
-}
-
-static char*
-fsclone(Fid *old, Fid *new)
-{
-	Aux *a;
-
-	a = emalloc(sizeof(*a));
-	*a = *(Aux*)old->aux;
-	if(a->s)
-		s_incref(a->s);
-	if(a->w)
-		incref(a->w);
-	if(a->map)
-		incref(a->map);
-	if(a->name)
-		s_incref(a->name);
-	new->aux = a;
-	new->qid = old->qid;
-
-	return nil;
-}
-
-static void
-fsdestroyfid(Fid *fid)
-{
-	Aux *a;
-
-	a = fid->aux;
-	if(a==nil)
-		return;
-
-	if(a->name)
-		s_free(a->name);
-	if(a->map)
-		closemap(a->map);
-	if(a->s)
-		s_free(a->s);
-	if(a->w)
-		closewhist(a->w);
-	free(a);
-	fid->aux = nil;
-}
-
-static void
-fillstat(Dir *d, uint64_t path, uint32_t tm, uint32_t length)
-{
-	char tmp[32], *p;
-	int type;
-
-	memset(d, 0, sizeof(Dir));
-	d->uid = estrdup9p("wiki");
-	d->gid = estrdup9p("wiki");
-
-	switch(qidtype(path)){
-	case Droot:
-	case D1st:
-	case D2nd:
-		type = QTDIR;
-		break;
-	default:
-		type = 0;
-		break;
-	}
-	d->qid = (Qid){path, tm, type};
-
-	d->atime = d->mtime = tm;
-	d->length = length;
-	if(qidfile(path) == Qedithtml)
-		d->atime = d->mtime = time(0);
-
-	switch(qidtype(path)){
-	case Droot:
-		d->name = estrdup("/");
-		d->mode = DMDIR|0555;
-		break;
-
-	case D1st:
-		d->name = numtoname(qidnum(path));
-		if(d->name == nil)
-			d->name = estrdup("<dead>");
-		for(p=d->name; *p; p++)
-			if(*p==' ')
-				*p = '_';
-		d->mode = DMDIR|0555;
-		break;
-
-	case D2nd:
-		snprint(tmp, sizeof tmp, "%lu", tm);
-		d->name = estrdup(tmp);
-		d->mode = DMDIR|0555;
-		break;
-
-	case Fmap:
-		d->name = estrdup("map");
-		d->mode = 0666;
-		break;
-
-	case Fnew:
-		d->name = estrdup("new");
-		d->mode = 0666;
-		break;
-
-	case F1st:
-		d->name = estrdup(filelist[qidfile(path)]);
-		d->mode = 0444;
-		break;
-
-	case F2nd:
-		d->name = estrdup(filelist[qidfile(path)]);
-		d->mode = 0444;
-		break;
-
-	default:
-		print("bad qid path 0x%.8llux\n", path);
-		break;
-	}
-}
-
-static void
-fsstat(Req *r)
-{
-	Aux *a;
-	Fid *fid;
-	uint32_t t;
-
-	t = 0;
-	fid = r->fid;
-	if((a = fid->aux) && a->w)
-		t = a->w->doc[a->n].time;
-
-	fillstat(&r->d, fid->qid.path, t, a->s ? s_len(a->s) : 0);
-	respond(r, nil);
-}
-
-typedef struct Bogus Bogus;
-struct Bogus {
-	uint64_t path;
-	Aux *a;
-};
-
-static int
-rootgen(int i, Dir *d, void *aux)
-{
-	Aux *a;
-	Bogus *b;
-
-	b = aux;
-	a = b->a;
-	switch(i){
-	case 0:	/* new */
-		fillstat(d, mkqid(Fnew, 0, 0, 0), a->map->t, 0);
-		return 0;
-	case 1:	/* map */
-		fillstat(d, mkqid(Fmap, 0, 0, 0), a->map->t, 0);
-		return 0;
-	default:	/* first-level directory */
-		i -= 2;
-		if(i >= a->map->nel)
-			return -1;
-		fillstat(d, mkqid(D1st, a->map->el[i].n, 0, 0), a->map->t, 0);
-		return 0;
-	}
-}
-
-static int
-firstgen(int i, Dir *d, void *aux)
-{
-	uint32_t t;
-	Bogus *b;
-	int num;
-	Aux *a;
-
-	b = aux;
-	num = qidnum(b->path);
-	a = b->a;
-	t = a->w->doc[a->n].time;
-
-	if(i < Nfile){	/* file in first-level directory */
-		fillstat(d, mkqid(F1st, num, 0, i), t, 0);
-		return 0;
-	}
-	i -= Nfile;
-
-	if(i < a->w->ndoc){	/* second-level (history) directory */
-		fillstat(d, mkqid(D2nd, num, i, 0), a->w->doc[i].time, 0);
-		return 0;
-	}
-	//i -= a->w->ndoc;
-
-	return -1;
-}
-
-static int
-secondgen(int i, Dir *d, void *aux)
-{
-	Bogus *b;
-	uint64_t path;
-	Aux *a;
-
-	b = aux;
-	path = b->path;
-	a = b->a;
-
-	if(i <= Qraw){	/* index.html, index.txt, raw */
-		fillstat(d, mkqid(F2nd, qidnum(path), qidvers(path), i), a->w->doc[a->n].time, 0);
-		return 0;
-	}
-	//i -= Qraw;
-
-	return -1;
-}
-
-static void
-fsread(Req *r)
-{
-	char *t, *s;
-	uint64_t path;
-	Aux *a;
-	Bogus b;
-
-	a = r->fid->aux;
-	path = r->fid->qid.path;
-	b.a = a;
-	b.path = path;
-	switch(qidtype(path)){
-	default:
-		respond(r, "cannot happen (bad qid)");
-		return;
-
-	case Droot:
-		if(a == nil || a->map == nil){
-			respond(r, "cannot happen (no map)");
-			return;
-		}
-		dirread9p(r, rootgen, &b);
-		respond(r, nil);
-		return;
-
-	case D1st:
-		if(a == nil || a->w == nil){
-			respond(r, "cannot happen (no wh)");
-			return;
-		}
-		dirread9p(r, firstgen, &b);
-		respond(r, nil);
-		return;
-
-	case D2nd:
-		dirread9p(r, secondgen, &b);
-		respond(r, nil);
-		return;
-
-	case Fnew:
-		if(a->s){
-			respond(r, "protocol botch");
-			return;
-		}
-		/* fall through */
-	case Fmap:
-		t = numtoname(a->n);
-		if(t == nil){
-			respond(r, "unknown name");
-			return;
-		}
-		for(s=t; *s; s++)
-			if(*s == ' ')
-				*s = '_';
-		readstr(r, t);
-		free(t);
-		respond(r, nil);
-		return;
-
-	case F1st:
-	case F2nd:
-		if(a == nil || a->s == nil){
-			respond(r, "cannot happen (no s)");
-			return;
-		}
-		readbuf(r, s_to_c(a->s), s_len(a->s));
-		respond(r, nil);
-		return;
-	}
-}
-
-typedef struct Sread Sread;
-struct Sread {
-	char *rp;
-};
-
-static char*
-Srdline(void *v, int c)
-{
-	char *p, *rv;
-	Sread *s;
-
-	s = v;
-	if(s->rp == nil)
-		rv = nil;
-	else if(p = strchr(s->rp, c)){
-		*p = '\0';
-		rv = s->rp;
-		s->rp = p+1;
-	}else{
-		rv = s->rp;
-		s->rp = nil;
-	}
-	return rv;
-}
-
-static void
-responderrstr(Req *r)
-{
-	char buf[ERRMAX];
-
-	rerrstr(buf, sizeof buf);
-	if(buf[0] == '\0')
-		strcpy(buf, "unknown error");
-	respond(r, buf);
-}
-
-static void
-fswrite(Req *r)
-{
-	char *author, *comment, *net, *err, *p, *title, tmp[40];
-	int rv, n;
-	uint32_t t;
-	Aux *a;
-	Fid *fid;
-	Sread s;
-	String *stmp;
-	Whist *w;
-
-	fid = r->fid;
-	a = fid->aux;
-	switch(qidtype(fid->qid.path)){
-	case Fmap:
-		stmp = s_nappend(s_reset(nil), r->ifcall.data, r->ifcall.count);
-		a->n = nametonum(s_to_c(stmp));
-		s_free(stmp);
-		if(a->n < 0)
-			respond(r, "name not found");
-		else
-			respond(r, nil);
-		return;
-	case Fnew:
-		break;
-	default:
-		respond(r, "cannot happen");
-		return;
-	}
-
-	if(a->s == nil){
-		respond(r, "protocol botch");
-		return;
-	}
-	if(r->ifcall.count==0){	/* do final processing */
-		s.rp = s_to_c(a->s);
-		w = nil;
-		err = "bad format";
-		if((title = Srdline(&s, '\n')) == nil){
-		Error:
-			if(w)
-				closewhist(w);
-			s_free(a->s);
-			a->s = nil;
-			respond(r, err);
-			return;
-		}
-
-		w = emalloc(sizeof(*w));
-		incref(w);
-		w->title = estrdup(title);
-
-		t = 0;
-		author = estrdup(s_to_c(a->name));
-
-		comment = nil;
-		while(s.rp && *s.rp && *s.rp != '\n'){
-			p = Srdline(&s, '\n');
-			assert(p != nil);
-			switch(p[0]){
-			case 'A':
-				free(author);
-				author = estrdup(p+1);
-				break;
-			case 'D':
-				t = strtoul(p+1, &p, 10);
-				if(*p != '\0')
-					goto Error;
-				break;
-			case 'C':
-				free(comment);
-				comment = estrdup(p+1);
-				break;
-			}
-		}
-
-		w->doc = emalloc(sizeof(w->doc[0]));
-		w->doc->time = time(0);
-		w->doc->comment = comment;
-
-		if(net = r->pool->srv->aux){
-			p = emalloc(strlen(author)+10+strlen(net));
-			strcpy(p, author);
-			strcat(p, " (");
-			strcat(p, net);
-			strcat(p, ")");
-			free(author);
-			author = p;
-		}
-		w->doc->author = author;
-
-		if((w->doc->wtxt = Brdpage(Srdline, &s)) == nil){
-			err = "empty document";
-			goto Error;
-		}
-
-		w->ndoc = 1;
-		if((n = allocnum(w->title, 0)) < 0)
-			goto Error;
-		sprint(tmp, "D%lu\n", w->doc->time);
-		a->s = s_reset(a->s);
-		a->s = doctext(a->s, w->doc);
-		rv = writepage(n, t, a->s, w->title);
-		s_free(a->s);
-		a->s = nil;
-		a->n = n;
-		closewhist(w);
-		if(rv < 0)
-			responderrstr(r);
-		else
-			respond(r, nil);
-		return;
-	}
-
-	if(s_len(a->s)+r->ifcall.count > Maxfile){
-		respond(r, "file too large");
-		s_free(a->s);
-		a->s = nil;
-		return;
-	}
-	a->s = s_nappend(a->s, r->ifcall.data, r->ifcall.count);
-	r->ofcall.count = r->ifcall.count;
-	respond(r, nil);
-}
-
-Srv wikisrv = {
-.attach=	fsattach,
-.destroyfid=	fsdestroyfid,
-.clone=	fsclone,
-.walk1=	fswalk1,
-.open=	fsopen,
-.read=	fsread,
-.write=	fswrite,
-.stat=	fsstat,
-};
-
-void
-usage(void)
-{
-	fprint(2, "usage: wikifs [-D] [-a addr]... [-m mtpt] [-p perm] [-s service] dir\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	char **addr;
-	int i, naddr;
-	char *buf;
-	char *service, *mtpt;
-	ulong perm;
-	Dir d, *dp;
-	Srv *s;
-
-	naddr = 0;
-	addr = nil;
-	perm = 0;
-	service = nil;
-	mtpt = "/mnt/wiki";
-	ARGBEGIN{
-	case 'D':
-		chatty9p++;
-		break;
-	case 'a':
-		if(naddr%8 == 0)
-			addr = erealloc(addr, (naddr+8)*sizeof(addr[0]));
-		addr[naddr++] = EARGF(usage());
-		break;
-	case 'm':
-		mtpt = EARGF(usage());
-		break;
-	case 'M':
-		mtpt = nil;
-		break;
-	case 'p':
-		perm = strtoul(EARGF(usage()), nil, 8);
-		break;
-	case 's':
-		service = EARGF(usage());
-		break;
-	default:
-		usage();
-		break;
-	}ARGEND
-
-	if(argc != 1)
-		usage();
-
-	if((dp = dirstat(argv[0])) == nil)
-		sysfatal("dirstat %s: %r", argv[0]);
-	if((dp->mode&DMDIR) == 0)
-		sysfatal("%s: not a directory", argv[0]);
-	free(dp);
-	wikidir = argv[0];
-
-	currentmap(0);
-
-	for(i=0; i<naddr; i++)
-		listensrv(&wikisrv, addr[i]);
-
-	s = emalloc(sizeof *s);
-	*s = wikisrv;
-	postmountsrv(s, service, mtpt, MREPL|MCREATE);
-	if(perm){
-		buf = emalloc9p(5+strlen(service)+1);
-		strcpy(buf, "/srv/");
-		strcat(buf, service);
-		nulldir(&d);
-		d.mode = perm;
-		if(dirwstat(buf, &d) < 0)
-			fprint(2, "wstat: %r\n");
-		free(buf);
-	}
-	exits(nil);
-}

+ 0 - 710
sys/src/cmd/wikifs/io.c

@@ -1,710 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-/*
- * I/O for a Wiki document set.
- *
- * The files are kept in one flat directory.
- * There are three files for each document:
- *	nnn	- current version of the document
- *	nnn.hist	- history (all old versions) of the document
- *		append-only
- *	L.nnn	- write lock file for the document
- *
- * At the moment, since we don't have read/write locks
- * in the file system, we use the L.nnn file as a read lock too.
- * It's a hack but there aren't supposed to be many readers
- * anyway.
- *
- * The nnn.hist file is in the format read by Brdwhist.
- * The nnn file is in that format too, but only contains the
- * last entry of the nnn.hist file.
- *
- * In addition to this set of files, there is an append-only
- * map file that provides a mapping between numbers and titles.
- * The map file is a sequence of lines of the form
- *	nnn Title Here
- * The lock file L.map must be held to add to the end, to
- * make sure that the numbers are allocated sequentially.
- *
- * We assume that writes to the map file will fit in one message,
- * so that we don't have to read-lock the file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-enum {
-	Nhash = 64,
-	Mcache = 128,
-};
-
-typedef struct Wcache Wcache;
-struct Wcache {
-	int n;
-	ulong use;
-	RWLock;
-	ulong tcurrent;
-	ulong thist;
-	Whist *hist;
-	Whist *current;
-	Qid qid;
-	Qid qidhist;
-	Wcache *hash;
-};
-
-static RWLock cachelock;
-static Wcache *tab[Nhash];
-int ncache;
-
-void
-closewhist(Whist *wh)
-{
-	int i;
-
-	if(wh && decref(wh) == 0){
-		free(wh->title);
-		for(i=0; i<wh->ndoc; i++){
-			free(wh->doc[i].author);
-			free(wh->doc[i].comment);
-			freepage(wh->doc[i].wtxt);
-		}
-		free(wh->doc);
-		free(wh);
-	}
-}
-
-void
-freepage(Wpage *p)
-{
-	Wpage *next;
-
-	for(; p; p=next){
-		next = p->next;
-		free(p->text);
-		free(p->url);
-		free(p);
-	}
-}
-
-static Wcache*
-findcache(int n)
-{
-	Wcache *w;
-
-	for(w=tab[n%Nhash]; w; w=w->hash)
-		if(w->n == n){
-			w->use = time(0);
-			return w;
-		}
-	return nil;
-}
-
-static int
-getlock(char *lock)
-{
-	char buf[ERRMAX];
-	int i, fd;
-	enum { SECS = 200 };
-
-	for(i=0; i<SECS*10; i++){
-		fd = wcreate(lock, ORDWR, DMEXCL|0666);
-		if(fd >= 0)
-			return fd;
-		buf[0] = '\0';
-		rerrstr(buf, sizeof buf);
-		if(strstr(buf, "locked") == nil)
-			break;
-		sleep(1000/10);
-	}
-	werrstr("couldn't acquire lock %s: %r", lock);
-	return -1;
-}
-
-static Whist*
-readwhist(char *file, char *lock, Qid *qid)
-{
-	int lfd;
-	Biobuf *b;
-	Dir *d;
-	Whist *wh;
-
-	if((lfd=getlock(lock)) < 0)	// LOG?
-		return nil;
-
-	if(qid){
-		if((d = wdirstat(file)) == nil){
-			close(lfd);
-			return nil;
-		}
-		*qid = d->qid;
-		free(d);
-	}
-
-	if((b = wBopen(file, OREAD)) == nil){	//LOG?
-		close(lfd);
-		return nil;
-	}
-
-	wh = Brdwhist(b);
-
-	Bterm(b);
-	close(lfd);
-	return wh;
-}
-
-static void
-gencurrent(Wcache *w, Qid *q, char *file, char *lock, uint32_t *t,
-	   Whist **wp, int n)
-{
-	Dir *d;
-	Whist *wh;
-
-	if(*wp && *t+Tcache >= time(0))
-		return;
-
-	wlock(w);
-	if(*wp && *t+Tcache >= time(0)){
-		wunlock(w);
-		return;
-	}
-
-	if(((d = wdirstat(file)) == nil) || (d->qid.path==q->path && d->qid.vers==q->vers)){
-		*t = time(0);
-		wunlock(w);
-		free(d);
-		return;
-	}
-
-	free(d);
-	if(wh = readwhist(file, lock, q)){
-		wh->n = n;
-		*t = time(0);
-		closewhist(*wp);
-		*wp = wh;
-	}
-else fprint(2, "error file=%s lock=%s %r\n", file, lock);
-	wunlock(w);
-}
-
-static void
-current(Wcache *w)
-{
-	char tmp[40];
-	char tmplock[40];
-
-	sprint(tmplock, "d/L.%d", w->n);
-	sprint(tmp, "d/%d", w->n);
-	gencurrent(w, &w->qid, tmp, tmplock, &w->tcurrent, &w->current, w->n);
-}
-
-static void
-currenthist(Wcache *w)
-{
-	char hist[40], lock[40];
-
-	sprint(hist, "d/%d.hist", w->n);
-	sprint(lock, "d/L.%d", w->n);
-
-	gencurrent(w, &w->qidhist, hist, lock, &w->thist, &w->hist, w->n);
-}
-
-void
-voidcache(int n)
-{
-	Wcache *c;
-
-	rlock(&cachelock);
-	if(c = findcache(n)){
-		wlock(c);
-		c->tcurrent = 0;
-		c->thist = 0;
-		/* aggressively free memory */
-		closewhist(c->hist);
-		c->hist = nil;
-		closewhist(c->current);
-		c->current = nil;
-		wunlock(c);
-	}
-	runlock(&cachelock);
-}
-
-static Whist*
-getcache(int n, int hist)
-{
-	int i, isw;
-	uint32_t t;
-	Wcache *c, **cp, **evict;
-	Whist *wh;
-
-	isw = 0;
-	rlock(&cachelock);
-	if(c = findcache(n)){
-	Found:
-		current(c);
-		if(hist)
-			currenthist(c);
-		rlock(c);
-		if(hist)
-			wh = c->hist;
-		else
-			wh = c->current;
-		if(wh)
-			incref(wh);
-		runlock(c);
-		if(isw)
-			wunlock(&cachelock);
-		else
-			runlock(&cachelock);
-		return wh;
-	}
-	runlock(&cachelock);
-
-	wlock(&cachelock);
-	if(c = findcache(n)){
-		isw = 1;	/* better to downgrade lock but can't */
-		goto Found;
-	}
-
-	if(ncache < Mcache){
-	Alloc:
-		c = emalloc(sizeof *c);
-		ncache++;
-	}else{
-		/* find something to evict. */
-		t = ~0;
-		evict = nil;
-		for(i=0; i<Nhash; i++){
-			for(cp=&tab[i], c=*cp; c; cp=&c->hash, c=*cp){
-				if(c->use < t
-				&& (!c->hist || c->hist->ref==1)
-				&& (!c->current || c->current->ref==1)){
-					evict = cp;
-					t = c->use;
-				}
-			}
-		}
-
-		if(evict == nil){
-			fprint(2, "wikifs: nothing to evict\n");
-			goto Alloc;
-		}
-
-		c = *evict;
-		*evict = c->hash;
-
-		closewhist(c->current);
-		closewhist(c->hist);
-		memset(c, 0, sizeof *c);
-	}
-
-	c->n = n;
-	c->hash = tab[n%Nhash];
-	tab[n%Nhash] = c;
-	isw = 1;
-	goto Found;
-}
-
-Whist*
-getcurrent(int n)
-{
-	return getcache(n, 0);
-}
-
-Whist*
-gethistory(int n)
-{
-	return getcache(n, 1);
-}
-
-RWLock maplock;
-Map *map;
-
-static int
-mapcmp(const void *va, const void *vb)
-{
-	Mapel *a, *b;
-
-	a = (Mapel*)va;
-	b = (Mapel*)vb;
-
-	return strcmp(a->s, b->s);
-}
-
-void
-closemap(Map *m)
-{
-	if(decref(m)==0){
-		free(m->buf);
-		free(m->el);
-		free(m);
-	}
-}
-
-void
-currentmap(int force)
-{
-	char *p, *q, *r;
-	int lfd, fd, m, n;
-	Dir *d;
-	Map *nmap;
-	char *err = nil;
-
-	lfd = -1;
-	fd = -1;
-	d = nil;
-	nmap = nil;
-	if(!force && map && map->t+Tcache >= time(0))
-		return;
-
-	wlock(&maplock);
-	if(!force && map && map->t+Tcache >= time(0))
-		goto Return;
-
-	if((lfd = getlock("d/L.map")) < 0){
-		err = "can't lock";
-		goto Return;
-	}
-
-	if((d = wdirstat("d/map")) == nil)
-		goto Return;
-
-	if(map && d->qid.path == map->qid.path && d->qid.vers == map->qid.vers){
-		map->t = time(0);
-		goto Return;
-	}
-
-	if(d->length > Maxmap){
-		//LOG
-		err = "too long";
-		goto Return;
-	}
-
-	if((fd = wopen("d/map", OREAD)) < 0)
-		goto Return;
-
-	nmap = emalloc(sizeof *nmap);
-	nmap->buf = emalloc(d->length+1);
-	n = readn(fd, nmap->buf, d->length);
-	if(n != d->length){
-		err = "bad length";
-		goto Return;
-	}
-	nmap->buf[n] = '\0';
-
-	n = 0;
-	for(p=nmap->buf; p; p=strchr(p+1, '\n'))
-		n++;
-	nmap->el = emalloc(n*sizeof(nmap->el[0]));
-
-	m = 0;
-	for(p=nmap->buf; p && *p && m < n; p=q){
-		if(q = strchr(p+1, '\n'))
-			*q++ = '\0';
-		nmap->el[m].n = strtol(p, &r, 10);
-		if(*r == ' ')
-			r++;
-		else
-			{}//LOG?
-		nmap->el[m].s = strcondense(r, 1);
-		m++;
-	}
-	//LOG if m != n
-
-	nmap->qid = d->qid;
-	nmap->t = time(0);
-	nmap->nel = m;
-	qsort(nmap->el, nmap->nel, sizeof(nmap->el[0]), mapcmp);
-	if(map)
-		closemap(map);
-	map = nmap;
-	incref(map);
-	nmap = nil;
-
-Return:
-	free(d);
-	if(nmap){
-		free(nmap->el);
-		free(nmap->buf);
-		free(nmap);
-	}
-	if(map == nil)
-		sysfatal("cannot get map: %s: %r", err);
-
-	if(fd >= 0)
-		close(fd);
-	if(lfd >= 0)
-		close(lfd);
-	wunlock(&maplock);
-}
-
-int
-allocnum(char *title, int mustbenew)
-{
-	char *p, *q;
-	int lfd, fd, n;
-	Biobuf b;
-
-	if(strcmp(title, "map")==0 || strcmp(title, "new")==0){
-		werrstr("reserved title name");
-		return -1;
-	}
-
-	if(title[0]=='\0' || strpbrk(title, "/<>:?")){
-		werrstr("invalid character in name");
-		return -1;
-	}
-	if((n = nametonum(title)) >= 0){
-		if(mustbenew){
-			werrstr("duplicate title");
-			return -1;
-		}
-		return n;
-	}
-
-	title = estrdup(title);
-	strcondense(title, 1);
-	strlower(title);
-	if(strchr(title, '\n') || strlen(title) > 200){
-		werrstr("bad title");
-		free(title);
-		return -1;
-	}
-
-	if((lfd = getlock("d/L.map")) < 0){
-		free(title);
-		return -1;
-	}
-
-	if((fd = wopen("d/map", ORDWR)) < 0){	// LOG?
-		close(lfd);
-		free(title);
-		return -1;
-	}
-
-	/*
-	 * What we really need to do here is make sure the
-	 * map is up-to-date, then make sure the title isn't
-	 * taken, and then add it, all without dropping the locks.
-	 *
-	 * This turns out to be a mess when you start adding
-	 * all the necessary dolock flags, so instead we just
-	 * read through the file ourselves, and let our
-	 * map catch up on its own.
-	 */
-	Binit(&b, fd, OREAD);
-	n = 0;
-	while(p = Brdline(&b, '\n')){
-		p[Blinelen(&b)-1] = '\0';
-		n = atoi(p)+1;
-		q = strchr(p, ' ');
-		if(q == nil)
-			continue;
-		if(strcmp(q+1, title) == 0){
-			free(title);
-			close(fd);
-			close(lfd);
-			if(mustbenew){
-				werrstr("duplicate title");
-				return -1;
-			}else
-				return n;
-		}
-	}
-
-	seek(fd, 0, 2);	/* just in case it's not append only */
-	fprint(fd, "%d %s\n", n, title);
-	close(fd);
-	close(lfd);
-	free(title);
-	/* kick the map */
-	currentmap(1);
-	return n;
-}
-
-int
-nametonum(char *s)
-{
-	char *p;
-	int i, lo, hi, m, rv;
-
-	s = estrdup(s);
-	strlower(s);
-	for(p=s; *p; p++)
-		if(*p=='_')
-			*p = ' ';
-
-	currentmap(0);
-	rlock(&maplock);
-	lo = 0;
-	hi = map->nel;
-	while(hi-lo > 1){
-		m = (lo+hi)/2;
-		i = strcmp(s, map->el[m].s);
-		if(i < 0)
-			hi = m;
-		else
-			lo = m;
-	}
-	if(hi-lo == 1 && strcmp(s, map->el[lo].s)==0)
-		rv = map->el[lo].n;
-	else
-		rv = -1;
-	runlock(&maplock);
-	free(s);
-	return rv;
-}
-
-char*
-numtoname(int n)
-{
-	int i;
-	char *s;
-
-	currentmap(0);
-	rlock(&maplock);
-	for(i=0; i<map->nel; i++){
-		if(map->el[i].n==n)
-			break;
-	}
-	if(i==map->nel){
-		runlock(&maplock);
-		return nil;
-	}
-	s = estrdup(map->el[i].s);
-	runlock(&maplock);
-	return s;
-}
-
-Whist*
-getcurrentbyname(char *s)
-{
-	int n;
-
-	if((n = nametonum(s)) < 0)
-		return nil;
-	return getcache(n, 0);
-}
-
-static String*
-Brdstring(Biobuf *b)
-{
-	int32_t len;
-	String *s;
-	Dir *d;
-
-	d = dirfstat(Bfildes(b));
-	if (d == nil)	/* shouldn't happen, we just opened it */
-		len = 0;
-	else
-		len = d->length;
-	free(d);
-	s = s_newalloc(len);
-	s_read(b, s, len);
-	return s;
-}
-
-/*
- * Attempt to install a new page.  If t==0 we are creating.
- * Otherwise, we are editing and t must be set to the current
- * version (t is the version we started with) to avoid conflicting
- * writes.
- *
- * If there is a conflicting write, we still write the page to
- * the history file, but mark it as a failed write.
- */
-int
-writepage(int num, uint32_t t, String *s, char *title)
-{
-	char tmp[40], tmplock[40], err[ERRMAX], hist[40], *p;
-	int conflict, lfd, fd;
-	Biobuf *b;
-	String *os;
-
-	sprint(tmp, "d/%d", num);
-	sprint(tmplock, "d/L.%d", num);
-	sprint(hist, "d/%d.hist", num);
-	if((lfd = getlock(tmplock)) < 0)
-		return -1;
-
-	conflict = 0;
-	if(b = wBopen(tmp, OREAD)){
-		Brdline(b, '\n');	/* title */
-		if(p = Brdline(b, '\n'))		/* version */
-			p[Blinelen(b)-1] = '\0';
-		if(p==nil || p[0] != 'D'){
-			snprint(err, sizeof err, "bad format in extant file");
-			conflict = 1;
-		}else if(strtoul(p+1, 0, 0) != t){
-			os = Brdstring(b);	/* why read the whole file? */
-			p = strchr(s_to_c(s), '\n');
-			if(p!=nil && strcmp(p+1, s_to_c(os))==0){	/* ignore dup write */
-				close(lfd);
-				s_free(os);
-				Bterm(b);
-				return 0;
-			}
-			s_free(os);
-			snprint(err, sizeof err, "update conflict %lu != %s", t, p+1);
-			conflict = 1;
-		}
-		Bterm(b);
-	}else{
-		if(t != 0){
-			close(lfd);
-			werrstr("did not expect to create");
-			return -1;
-		}
-	}
-
-	if((fd = wopen(hist, OWRITE)) < 0){
-		if((fd = wcreate(hist, OWRITE, 0666)) < 0){
-			close(lfd);
-			return -1;
-		}else
-			fprint(fd, "%s\n", title);
-	}
-	if(seek(fd, 0, 2) < 0
-	|| (conflict && write(fd, "X\n", 2) != 2)
-	|| write(fd, s_to_c(s), s_len(s)) != s_len(s)){
-		close(fd);
-		close(lfd);
-		return -1;
-	}
-	close(fd);
-
-	if(conflict){
-		close(lfd);
-		voidcache(num);
-		werrstr(err);
-		return -1;
-	}
-
-	if((fd = wcreate(tmp, OWRITE, 0666)) < 0){
-		close(lfd);
-		voidcache(num);
-		return -1;
-	}
-	if(write(fd, title, strlen(title)) != strlen(title)
-	|| write(fd, "\n", 1) != 1
-	|| write(fd, s_to_c(s), s_len(s)) != s_len(s)){
-		close(fd);
-		close(lfd);
-		voidcache(num);
-		return -1;
-	}
-	close(fd);
-	close(lfd);
-	voidcache(num);
-	return 0;
-}

+ 0 - 21
sys/src/cmd/wikifs/lookup.c

@@ -1,21 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-void
-main(int argc, char **argv)
-{
-	print("%d\n", nametonum(argv[1]));
-}

+ 0 - 15
sys/src/cmd/wikifs/map.c

@@ -1,15 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"

+ 0 - 33
sys/src/cmd/wikifs/mkfile

@@ -1,33 +0,0 @@
-</$objtype/mkfile
-
-TARG=wikifs
-
-HFILES=wiki.h
-COFILES=\
-	io.$O\
-	parse.$O\
-	parsehist.$O\
-	tohtml.$O\
-	util.$O\
-	wdir.$O\
-
-OFILES=fs.$O $COFILES
-
-BIN=/$objtype/bin
-LIB=/$objtype/lib/lib9p.a #/$objtype/lib/libdebugmalloc.a
-
-UPDATE=\
-	mkfile\
-	$HFILES\
-	${OFILES:%.$O=%.c}\
-
-</sys/src/cmd/mkone
-
-$O.wiki2html: wiki2html.$O $COFILES
-	$LD -o $target $prereq
-
-$O.wiki2text: wiki2text.$O $COFILES
-	$LD -o $target $prereq
-
-$O.owikifs: ofs.$O $COFILES
-	$LD -o $target $prereq

+ 0 - 340
sys/src/cmd/wikifs/parse.c

@@ -1,340 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <ctype.h>
-#include <thread.h>
-#include "wiki.h"
-
-static Wpage*
-mkwtxt(int type, char *text)
-{
-	Wpage *w;
-
-	w = emalloc(sizeof(*w));
-	w->type = type;
-	w->text = text;
-	setmalloctag(w, getcallerpc(&type));
-	return w;
-}
-
-/*
- * turn runs of whitespace into single spaces,
- * eliminate whitespace at beginning and end.
- */
-char*
-strcondense(char *s, int cutbegin)
-{
-	char *r, *w, *es;
-	int inspace;
-
-	es = s+strlen(s);
-	inspace = cutbegin;
-	for(r=w=s; *r; r++){
-		if(isspace(*r)){
-			if(!inspace){
-				inspace=1;
-				*w++ = ' ';
-			}
-		}else{
-			inspace=0;
-			*w++ = *r;
-		}
-	}
-	assert(w <= es);
-	if(inspace && w>s){
-		--w;
-		*w = '\0';
-	}
-	else
-		*w = '\0';
-	return s;
-}
-
-/*
- * turn runs of Wplain into single Wplain.
- */
-static Wpage*
-wcondense(Wpage *wtxt)
-{
-	Wpage *ow, *w;
-
-	for(w=wtxt; w; ){
-		if(w->type == Wplain)
-			strcondense(w->text, 1);
-
-		if(w->type != Wplain || w->next==nil
-		|| w->next->type != Wplain){
-			w=w->next;
-			continue;
-		}
-
-		w->text = erealloc(w->text, strlen(w->text)+1+strlen(w->next->text)+1);
-		strcat(w->text, " ");
-		strcat(w->text, w->next->text);
-
-		ow = w->next;
-		w->next = ow->next;
-		ow->next = nil;
-		freepage(ow);
-	}
-	return wtxt;
-}
-
-/*
- * Parse a link, without the brackets.
- */
-static Wpage*
-mklink(char *s)
-{
-	char *q;
-	Wpage *w;
-
-	for(q=s; *q && *q != '|'; q++)
-		;
-
-	if(*q == '\0'){
-		w = mkwtxt(Wlink, estrdup(strcondense(s, 1)));
-		w->url = nil;
-	}else{
-		*q = '\0';
-		w = mkwtxt(Wlink, estrdup(strcondense(s, 1)));
-		w->url = estrdup(strcondense(q+1, 1));
-	}
-	setmalloctag(w, getcallerpc(&s));
-	return w;
-}
-
-/*
- * Parse Wplains, inserting Wlink nodes where appropriate.
- */
-static Wpage*
-wlink(Wpage *wtxt)
-{
-	char *p, *q, *r, *s;
-	Wpage *w, *nw;
-
-	for(w=wtxt; w; w=nw){
-		nw = w->next;
-		if(w->type != Wplain)
-			continue;
-		while(w->text[0]){
-			p = w->text;
-			for(q=p; *q && *q != '['; q++)
-				;
-			if(*q == '\0')
-				break;
-			for(r=q; *r && *r != ']'; r++)
-				;
-			if(*r == '\0')
-				break;
-			*q = '\0';
-			*r = '\0';
-			s = w->text;
-			w->text = estrdup(w->text);
-			w->next = mklink(q+1);
-			w = w->next;
-			w->next = mkwtxt(Wplain, estrdup(r+1));
-			free(s);
-			w = w->next;
-			w->next = nw;
-		}
-		assert(w->next == nw);
-	}
-	return wtxt;
-}
-
-static int
-ismanchar(int c)
-{
-	return ('a' <= c && c <= 'z')
-		|| ('A' <= c && c <= 'Z')
-		|| ('0' <= c && c <= '9')
-		|| c=='_' || c=='-' || c=='.' || c=='/'
-		|| (c < 0);	/* UTF */
-}
-
-static Wpage*
-findmanref(char *p, char **beginp, char **endp)
-{
-	char *q, *r;
-	Wpage *w;
-
-	q=p;
-	for(;;){
-		for(; q[0] && (q[0] != '(' || !isdigit(q[1]) || q[2] != ')'); q++)
-			;
-		if(*q == '\0')
-			break;
-		for(r=q; r>p && ismanchar(r[-1]); r--)
-			;
-		if(r==q){
-			q += 3;
-			continue;
-		}
-		*q = '\0';
-		w = mkwtxt(Wman, estrdup(r));
-		*beginp = r;
-		*q = '(';
-		w->section = q[1]-'0';
-		*endp = q+3;
-		setmalloctag(w, getcallerpc(&p));
-		return w;
-	}
-	return nil;
-}
-
-/*
- * Parse Wplains, looking for man page references.
- * This should be done by using a plumb(6)-style
- * control file rather than hard-coding things here.
- */
-static Wpage*
-wman(Wpage *wtxt)
-{
-	char *q, *r;
-	Wpage *w, *mw, *nw;
-
-	for(w=wtxt; w; w=nw){
-		nw = w->next;
-		if(w->type != Wplain)
-			continue;
-		while(w->text[0]){
-			if((mw = findmanref(w->text, &q, &r)) == nil)
-				break;
-			*q = '\0';
-			w->next = mw;
-			w = w->next;
-			w->next = mkwtxt(Wplain, estrdup(r));
-			w = w->next;
-			w->next = nw;
-		}
-		assert(w->next == nw);
-	}
-	return wtxt;
-}
-
-static int isheading(char *p) {
-	Rune r;
-	int hasupper=0;
-	while(*p) {
-		p+=chartorune(&r,p);
-		if(isupperrune(r))
-			hasupper=1;
-		else if(islowerrune(r))
-			return 0;
-	}
-	return hasupper;
-}
-
-Wpage*
-Brdpage(char *(*rdline)(void*,int), void *b)
-{
-	char *p, *c;
-	int waspara;
-	Wpage *w, **pw;
-
-	w = nil;
-	pw = &w;
-	waspara = 1;
-	while((p = rdline(b, '\n')) != nil){
-		if(p[0] != '!')
-			p = strcondense(p, 1);
-		if(p[0] == '\0'){
-			if(waspara==0){
-				waspara=1;
-				*pw = mkwtxt(Wpara, nil);
-				pw = &(*pw)->next;
-			}
-			continue;
-		}
-		waspara = 0;
-		switch(p[0]){
-		case '*':
-			*pw = mkwtxt(Wbullet, nil);
-			pw = &(*pw)->next;
-			*pw = mkwtxt(Wplain, estrdup(p+1));
-			pw = &(*pw)->next;
-			break;
-		case '!':
-			*pw = mkwtxt(Wpre, estrdup(p[1]==' '?p+2:p+1));
-			pw = &(*pw)->next;
-			break;
-		case '-':
-			for(c = p; *c != '\0'; c++) {
-				if(*c != '-') {
-					c = p;
-					break;
-				}
-			}
-
-			if( (c-p) > 4) {
-				*pw = mkwtxt(Whr, nil);
-				pw = &(*pw)->next;
-				break;
-			}
-			/* else fall thru */
-		default:
-			if(isheading(p)){
-				*pw = mkwtxt(Wheading, estrdup(p));
-				pw = &(*pw)->next;
-				continue;
-			}
-			*pw = mkwtxt(Wplain, estrdup(p));
-			pw = &(*pw)->next;
-			break;
-		}
-	}
-	if(w == nil)
-		werrstr("empty page");
-
-	*pw = nil;
-	w = wcondense(w);
-	w = wlink(w);
-	w = wman(w);
-	setmalloctag(w, getcallerpc(&rdline));
-
-	return w;
-}
-
-void
-printpage(Wpage *w)
-{
-	for(; w; w=w->next){
-		switch(w->type){
-		case Wpara:
-			print("para\n");
-			break;
-		case Wheading:
-			print("heading '%s'\n", w->text);
-			break;
-		case Wbullet:
-			print("bullet\n");
-			break;
-		case Wlink:
-			print("link '%s' '%s'\n", w->text, w->url);
-			break;
-		case Wman:
-			print("man %d %s\n", w->section, w->text);
-			break;
-		case Wplain:
-			print("plain '%s'\n", w->text);
-			break;
-		case Whr:
-			print("hr\n");
-			break;
-		case Wpre:
-			print("pre '%s'\n", w->text);
-			break;
-		}
-	}
-}

+ 0 - 138
sys/src/cmd/wikifs/parsehist.c

@@ -1,138 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-/*
- * Read a Wiki history file.
- * It's a title line then a sequence of Wiki files separated by headers.
- *
- * Ddate/time
- * #body
- * #...
- * #...
- * #...
- * etc.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-static char*
-Brdwline(void *vb, int sep)
-{
-	Biobufhdr *b;
-	char *p;
-
-	b = vb;
-	if(Bgetc(b) == '#'){
-		if(p = Brdline(b, sep))
-			p[Blinelen(b)-1] = '\0';
-		return p;
-	}else{
-		Bungetc(b);
-		return nil;
-	}
-}
-
-Whist*
-Brdwhist(Biobuf *b)
-{
-	int i, current, conflict, c, n;
-	char *author, *comment, *p, *title;
-	uint32_t t;
-	Wdoc *w;
-	Whist *h;
-
-	if((p = Brdline(b, '\n')) == nil){
-		werrstr("short read: %r");
-		return nil;
-	}
-
-	p[Blinelen(b)-1] = '\0';
-	p = strcondense(p, 1);
-	title = estrdup(p);
-
-	w = nil;
-	n = 0;
-	t = -1;
-	author = nil;
-	comment = nil;
-	conflict = 0;
-	current = 0;
-	while((c = Bgetc(b)) != Beof){
-		if(c != '#'){
-			p = Brdline(b, '\n');
-			if(p == nil)
-				break;
-			p[Blinelen(b)-1] = '\0';
-
-			switch(c){
-			case 'D':
-				t = strtoul(p, 0, 10);
-				break;
-			case 'A':
-				free(author);
-				author = estrdup(p);
-				break;
-			case 'C':
-				free(comment);
-				comment = estrdup(p);
-				break;
-			case 'X':
-				conflict = 1;
-			}
-		} else {	/* c=='#' */
-			Bungetc(b);
-			if(n%8 == 0)
-				w = erealloc(w, (n+8)*sizeof(w[0]));
-			w[n].time = t;
-			w[n].author = author;
-			w[n].comment = comment;
-			comment = nil;
-			author = nil;
-			w[n].wtxt = Brdpage(Brdwline, b);
-			w[n].conflict = conflict;
-			if(w[n].wtxt == nil)
-				goto Error;
-			if(!conflict)
-				current = n;
-			n++;
-			conflict = 0;
-			t = -1;
-		}
-	}
-	if(w==nil)
-		goto Error;
-
-	free(comment);
-	free(author);
-	h = emalloc(sizeof *h);
-	h->title = title;
-	h->doc = w;
-	h->ndoc = n;
-	h->current = current;
-	incref(h);
-	setmalloctag(h, getcallerpc(&b));
-	return h;
-
-Error:
-	free(title);
-	free(author);
-	free(comment);
-	for(i=0; i<n; i++){
-		free(w[i].author);
-		free(w[i].comment);
-		freepage(w[i].wtxt);
-	}
-	free(w);
-	return nil;
-}

+ 0 - 61
sys/src/cmd/wikifs/testwrite.c

@@ -1,61 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-char *wikidir = ".";
-
-void
-usage(void)
-{
-	fprint(2, "usage: testwrite [-d dir] wikifile n\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	ulong t;
-	int i;
-	Biobuf *b;
-	String *h;
-	Whist *doc;
-	char tmp[20];
-
-	t = 0;
-	ARGBEGIN{
-	case 't':
-		t = strtoul(EARGF(usage()), 0, 0);
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc != 2)
-		usage();
-
-	if((b = Bopen(argv[0], OREAD)) == nil)
-		sysfatal("Bopen: %r");
-
-	if((doc = Brdwhist(b)) == nil)
-		sysfatal("Brdwtxt: %r");
-
-	sprint(tmp, "D%lu\n", time(0));
-	if((h = pagetext(s_copy(tmp), (doc->doc+doc->ndoc-1)->wtxt, 1))==nil)
-		sysfatal("wiki2text: %r");
-
-	if(writepage(atoi(argv[1]), t, h, doc->title) <0)
-		sysfatal("writepage: %r");
-	exits(0);
-}

+ 0 - 834
sys/src/cmd/wikifs/tohtml.c

@@ -1,834 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-/*
- * Get HTML and text templates from underlying file system.
- * Caches them, which means changes don't take effect for
- * up to Tcache seconds after they are made.
- *
- * If the files are deleted, we keep returning the last
- * known copy.
- */
-enum {
-	WAIT = 60
-};
-
-static char *name[2*Ntemplate] = {
- [Tpage] =		"page.html",
- [Tedit] =		"edit.html",
- [Tdiff] =		"diff.html",
- [Thistory] =		"history.html",
- [Tnew] =		"new.html",
- [Toldpage] =		"oldpage.html",
- [Twerror] =		"werror.html",
- [Ntemplate+Tpage] =	"page.txt",
- [Ntemplate+Tdiff] =	"diff.txt",
- [Ntemplate+Thistory] =	"history.txt",
- [Ntemplate+Toldpage] =	"oldpage.txt",
- [Ntemplate+Twerror] =	"werror.txt",
-};
-
-static struct {
-	RWLock;
-	String *s;
-	ulong t;
-	Qid qid;
-} cache[2*Ntemplate];
-
-static void
-cacheinit(void)
-{
-	int i;
-	static int x;
-	static Lock l;
-
-	if(x)
-		return;
-	lock(&l);
-	if(x){
-		unlock(&l);
-		return;
-	}
-
-	for(i=0; i<2*Ntemplate; i++)
-		if(name[i])
-			cache[i].s = s_copy("");
-	x = 1;
-	unlock(&l);
-}
-
-static String*
-gettemplate(int type)
-{
-	int n;
-	Biobuf *b;
-	Dir *d;
-	String *s, *ns;
-
-	if(name[type]==nil)
-		return nil;
-
-	cacheinit();
-
-	rlock(&cache[type]);
-	if(0 && cache[type].t+Tcache >= time(0)){
-		s = s_incref(cache[type].s);
-		runlock(&cache[type]);
-		return s;
-	}
-	runlock(&cache[type]);
-
-//	d = nil;
-	wlock(&cache[type]);
-	if(0 && cache[type].t+Tcache >= time(0) || (d = wdirstat(name[type])) == nil)
-		goto Return;
-
-	if(0 && d->qid.vers == cache[type].qid.vers && d->qid.path == cache[type].qid.path){
-		cache[type].t = time(0);
-		goto Return;
-	}
-
-	if((b = wBopen(name[type], OREAD)) == nil)
-		goto Return;
-
-	ns = s_reset(nil);
-	do
-		n = s_read(b, ns, Bsize);
-	while(n > 0);
-	Bterm(b);
-	if(n < 0) {
-		s_free(ns);
-		goto Return;
-	}
-
-	s_free(cache[type].s);
-	cache[type].s = ns;
-	cache[type].qid = d->qid;
-	cache[type].t = time(0);
-
-Return:
-	free(d);
-	s = s_incref(cache[type].s);
-	wunlock(&cache[type]);
-	return s;
-}
-
-
-/*
- * Write wiki document in HTML.
- */
-static String*
-s_escappend(String *s, char *p, int pre)
-{
-	char *q;
-
-	while(q = strpbrk(p, pre ? "<>&" : " <>&")){
-		s = s_nappend(s, p, q-p);
-		switch(*q){
-		case '<':
-			s = s_append(s, "&lt;");
-			break;
-		case '>':
-			s = s_append(s, "&gt;");
-			break;
-		case '&':
-			s = s_append(s, "&amp;");
-			break;
-		case ' ':
-			s = s_append(s, "\n");
-		}
-		p = q+1;
-	}
-	s = s_append(s, p);
-	return s;
-}
-
-static char*
-mkurl(char *s, int ty)
-{
-	char *p, *q;
-
-	if(strncmp(s, "http:", 5)==0
-	|| strncmp(s, "https:", 6)==0
-	|| strncmp(s, "#", 1)==0
-	|| strncmp(s, "ftp:", 4)==0
-	|| strncmp(s, "mailto:", 7)==0
-	|| strncmp(s, "telnet:", 7)==0
-	|| strncmp(s, "file:", 5)==0)
-		return estrdup(s);
-
-	if(strchr(s, ' ')==nil && strchr(s, '@')!=nil){
-		p = emalloc(strlen(s)+8);
-		strcpy(p, "mailto:");
-		strcat(p, s);
-		return p;
-	}
-
-	if(ty == Toldpage)
-		p = smprint("../../%s", s);
-	else
-		p = smprint("../%s", s);
-
-	for(q=p; *q; q++)
-		if(*q==' ')
-			*q = '_';
-	return p;
-}
-
-int okayinlist[Nwtxt] =
-{
-	[Wbullet] =	1,
-	[Wlink] =	1,
-	[Wman] =	1,
-	[Wplain] =	1,
-};
-
-int okayinpre[Nwtxt] =
-{
-	[Wlink] =	1,
-	[Wman] =	1,
-	[Wpre] =	1,
-};
-
-int okayinpara[Nwtxt] =
-{
-	[Wpara] =	1,
-	[Wlink] =	1,
-	[Wman] =	1,
-	[Wplain] =	1,
-};
-
-char*
-nospaces(char *s)
-{
-	char *q;
-	s = strdup(s);
-	if(s == nil)
-		return nil;
-	for(q=s; *q; q++)
-		if(*q == ' ')
-			*q = '_';
-	return s;
-}
-
-String*
-pagehtml(String *s, Wpage *wtxt, int ty)
-{
-	char *p, tmp[40];
-	int inlist, inpara, inpre, t, tnext;
-	Wpage *w;
-
-	inlist = 0;
-	inpre = 0;
-	inpara = 0;
-
-	for(w=wtxt; w; w=w->next){
-		t = w->type;
-		tnext = Whr;
-		if(w->next)
-			tnext = w->next->type;
-
-		if(inlist && !okayinlist[t]){
-			inlist = 0;
-			s = s_append(s, "\n</li>\n</ul>\n");
-		}
-		if(inpre && !okayinpre[t]){
-			inpre = 0;
-			s = s_append(s, "</pre>\n");
-		}
-
-		switch(t){
-		case Wheading:
-			p = nospaces(w->text);
-			s = s_appendlist(s,
-				"\n<a name=\"", p, "\" /><h3>",
-				w->text, "</h3>\n", nil);
-			free(p);
-			break;
-
-		case Wpara:
-			if(inpara){
-				s = s_append(s, "\n</p>\n");
-				inpara = 0;
-			}
-			if(okayinpara[tnext]){
-				s = s_append(s, "\n<p class='para'>\n");
-				inpara = 1;
-			}
-			break;
-
-		case Wbullet:
-			if(!inlist){
-				inlist = 1;
-				s = s_append(s, "\n<ul>\n");
-			}else
-				s = s_append(s, "\n</li>\n");
-			s = s_append(s, "\n<li>\n");
-			break;
-
-		case Wlink:
-			if(w->url == nil)
-				p = mkurl(w->text, ty);
-			else
-				p = w->url;
-			s = s_appendlist(s, "<a href=\"", p, "\">", nil);
-			s = s_escappend(s, w->text, 0);
-			s = s_append(s, "</a>");
-			if(w->url == nil)
-				free(p);
-			break;
-
-		case Wman:
-			sprint(tmp, "%d", w->section);
-			s = s_appendlist(s,
-				"<a href=\"http://plan9.bell-labs.com/magic/man2html/",
-				tmp, "/", w->text, "\"><i>", w->text, "</i>(",
-				tmp, ")</a>", nil);
-			break;
-
-		case Wpre:
-			if(!inpre){
-				inpre = 1;
-				s = s_append(s, "\n<pre>\n");
-			}
-			s = s_escappend(s, w->text, 1);
-			s = s_append(s, "\n");
-			break;
-
-		case Whr:
-			s = s_append(s, "<hr />");
-			break;
-
-		case Wplain:
-			s = s_escappend(s, w->text, 0);
-			break;
-		}
-	}
-	if(inlist)
-		s = s_append(s, "\n</li>\n</ul>\n");
-	if(inpre)
-		s = s_append(s, "</pre>\n");
-	if(inpara)
-		s = s_append(s, "\n</p>\n");
-	return s;
-}
-
-static String*
-copythru(String *s, char **newp, int *nlinep, int l)
-{
-	char *oq, *q, *r;
-	int ol;
-
-	q = *newp;
-	oq = q;
-	ol = *nlinep;
-	while(ol < l){
-		if(r = strchr(q, '\n'))
-			q = r+1;
-		else{
-			q += strlen(q);
-			break;
-		}
-		ol++;
-	}
-	if(*nlinep < l)
-		*nlinep = l;
-	*newp = q;
-	return s_nappend(s, oq, q-oq);
-}
-
-static int
-dodiff(char *f1, char *f2)
-{
-	int p[2];
-
-	if(pipe(p) < 0){
-		return -1;
-	}
-
-	switch(fork()){
-	case -1:
-		return -1;
-
-	case 0:
-		close(p[0]);
-		dup(p[1], 1);
-		execl("/bin/diff", "diff", f1, f2, nil);
-		_exits(nil);
-	}
-	close(p[1]);
-	return p[0];
-}
-
-
-/* print document i grayed out, with only diffs relative to j in black */
-static String*
-s_diff(String *s, Whist *h, int i, int j)
-{
-	char *p, *q, *pnew;
-	int fdiff, fd1, fd2, n1, n2;
-	Biobuf b;
-	char fn1[40], fn2[40];
-	String *new, *old;
-	int nline;
-
-	if(j < 0)
-		return pagehtml(s, h->doc[i].wtxt, Tpage);
-
-	strcpy(fn1, "/tmp/wiki.XXXXXX");
-	strcpy(fn2, "/tmp/wiki.XXXXXX");
-	if((fd1 = opentemp(fn1)) < 0 || (fd2 = opentemp(fn2)) < 0){
-		close(fd1);
-		s = s_append(s, "\nopentemp failed; sorry\n");
-		return s;
-	}
-
-	new = pagehtml(s_reset(nil), h->doc[i].wtxt, Tpage);
-	old = pagehtml(s_reset(nil), h->doc[j].wtxt, Tpage);
-	write(fd1, s_to_c(new), s_len(new));
-	write(fd2, s_to_c(old), s_len(old));
-
-	fdiff = dodiff(fn2, fn1);
-	if(fdiff < 0)
-		s = s_append(s, "\ndiff failed; sorry\n");
-	else{
-		nline = 0;
-		pnew = s_to_c(new);
-		Binit(&b, fdiff, OREAD);
-		while(p = Brdline(&b, '\n')){
-			if(p[0]=='<' || p[0]=='>' || p[0]=='-')
-				continue;
-			p[Blinelen(&b)-1] = '\0';
-			if((p = strpbrk(p, "acd")) == nil)
-				continue;
-			n1 = atoi(p+1);
-			if(q = strchr(p, ','))
-				n2 = atoi(q+1);
-			else
-				n2 = n1;
-			switch(*p){
-			case 'a':
-			case 'c':
-				s = s_append(s, "<span class='old_text'>");
-				s = copythru(s, &pnew, &nline, n1-1);
-				s = s_append(s, "</span><span class='new_text'>");
-				s = copythru(s, &pnew, &nline, n2);
-				s = s_append(s, "</span>");
-				break;
-			}
-		}
-		close(fdiff);
-		s = s_append(s, "<span class='old_text'>");
-		s = s_append(s, pnew);
-		s = s_append(s, "</span>");
-
-	}
-	s_free(new);
-	s_free(old);
-	close(fd1);
-	close(fd2);
-	return s;
-}
-
-static String*
-diffhtml(String *s, Whist *h)
-{
-	int i;
-	char tmp[50];
-	char *atime;
-
-	for(i=h->ndoc-1; i>=0; i--){
-		s = s_append(s, "<hr /><div class='diff_head'>\n");
-		if(i==h->current)
-			sprint(tmp, "index.html");
-		else
-			sprint(tmp, "%lu", h->doc[i].time);
-		atime = ctime(h->doc[i].time);
-		atime[strlen(atime)-1] = '\0';
-		s = s_appendlist(s,
-			"<a href=\"", tmp, "\">",
-			atime, "</a>", nil);
-		if(h->doc[i].author)
-			s = s_appendlist(s, ", ", h->doc[i].author, nil);
-		if(h->doc[i].conflict)
-			s = s_append(s, ", conflicting write");
-		s = s_append(s, "\n");
-		if(h->doc[i].comment)
-			s = s_appendlist(s, "<br /><i>", h->doc[i].comment, "</i>\n", nil);
-		s = s_append(s, "</div><hr />");
-		s = s_diff(s, h, i, i-1);
-	}
-	s = s_append(s, "<hr>");
-	return s;
-}
-
-static String*
-historyhtml(String *s, Whist *h)
-{
-	int i;
-	char tmp[40];
-	char *atime;
-
-	s = s_append(s, "<ul>\n");
-	for(i=h->ndoc-1; i>=0; i--){
-		if(i==h->current)
-			sprint(tmp, "index.html");
-		else
-			sprint(tmp, "%lu", h->doc[i].time);
-		atime = ctime(h->doc[i].time);
-		atime[strlen(atime)-1] = '\0';
-		s = s_appendlist(s,
-			"<li><a href=\"", tmp, "\">",
-			atime, "</a>", nil);
-		if(h->doc[i].author)
-			s = s_appendlist(s, ", ", h->doc[i].author, nil);
-		if(h->doc[i].conflict)
-			s = s_append(s, ", conflicting write");
-		s = s_append(s, "\n");
-		if(h->doc[i].comment)
-			s = s_appendlist(s, "<br><i>", h->doc[i].comment, "</i>\n", nil);
-	}
-	s = s_append(s, "</ul>");
-	return s;
-}
-
-String*
-tohtml(Whist *h, Wdoc *d, int ty)
-{
-	char *atime;
-	char *p, *q, ver[40];
-	int nsub;
-	Sub sub[3];
-	String *s, *t;
-
-	t = gettemplate(ty);
-	if(p = strstr(s_to_c(t), "PAGE"))
-		q = p+4;
-	else{
-		p = s_to_c(t)+s_len(t);
-		q = nil;
-	}
-
-	nsub = 0;
-	if(h){
-		sub[nsub] = (Sub){ "TITLE", h->title };
-		nsub++;
-	}
-	if(d){
-		sprint(ver, "%lu", d->time);
-		sub[nsub] = (Sub){ "VERSION", ver };
-		nsub++;
-		atime = ctime(d->time);
-		atime[strlen(atime)-1] = '\0';
-		sub[nsub] = (Sub){ "DATE", atime };
-		nsub++;
-	}
-
-	s = s_reset(nil);
-	s = s_appendsub(s, s_to_c(t), p-s_to_c(t), sub, nsub);
-	switch(ty){
-	case Tpage:
-	case Toldpage:
-		s = pagehtml(s, d->wtxt, ty);
-		break;
-	case Tedit:
-		s = pagetext(s, d->wtxt, 0);
-		break;
-	case Tdiff:
-		s = diffhtml(s, h);
-		break;
-	case Thistory:
-		s = historyhtml(s, h);
-		break;
-	case Tnew:
-	case Twerror:
-		break;
-	}
-	if(q)
-		s = s_appendsub(s, q, strlen(q), sub, nsub);
-	s_free(t);
-	return s;
-}
-
-enum {
-	LINELEN = 70,
-};
-
-static String*
-s_appendbrk(String *s, char *p, char *prefix, int dosharp)
-{
-	char *e, *w, *x;
-	int first, l;
-	Rune r;
-
-	first = 1;
-	while(*p){
-		s = s_append(s, p);
-		e = strrchr(s_to_c(s), '\n');
-		if(e == nil)
-			e = s_to_c(s);
-		else
-			e++;
-		if(utflen(e) <= LINELEN)
-			break;
-		x = e; l=LINELEN;
-		while(l--)
-			x+=chartorune(&r, x);
-		x = strchr(x, ' ');
-		if(x){
-			*x = '\0';
-			w = strrchr(e, ' ');
-			*x = ' ';
-		}else
-			w = strrchr(e, ' ');
-
-		if(w-s_to_c(s) < strlen(prefix))
-			break;
-
-		x = estrdup(w+1);
-		*w = '\0';
-		s->ptr = w;
-		s_append(s, "\n");
-		if(dosharp)
-			s_append(s, "#");
-		s_append(s, prefix);
-		if(!first)
-			free(p);
-		first = 0;
-		p = x;
-	}
-	if(!first)
-		free(p);
-	return s;
-}
-
-static void
-s_endline(String *s, int dosharp)
-{
-	if(dosharp){
-		if(s->ptr == s->base+1 && s->ptr[-1] == '#')
-			return;
-
-		if(s->ptr > s->base+1 && s->ptr[-1] == '#' && s->ptr[-2] == '\n')
-			return;
-		s_append(s, "\n#");
-	}else{
-		if(s->ptr > s->base+1 && s->ptr[-1] == '\n')
-			return;
-		s_append(s, "\n");
-	}
-}
-
-String*
-pagetext(String *s, Wpage *page, int dosharp)
-{
-	int inlist, inpara;
-	char *prefix, *sharp, tmp[40];
-	String *t;
-	Wpage *w;
-
-	inlist = 0;
-	inpara = 0;
-	prefix = "";
-	sharp = dosharp ? "#" : "";
-	s = s_append(s, sharp);
-	for(w=page; w; w=w->next){
-		switch(w->type){
-		case Wheading:
-			if(inlist){
-				prefix = "";
-				inlist = 0;
-			}
-			s_endline(s, dosharp);
-			if(!inpara){
-				inpara = 1;
-				s = s_appendlist(s, "\n", sharp, nil);
-			}
-			s = s_appendlist(s, w->text, "\n", sharp, "\n", sharp, nil);
-			break;
-
-		case Wpara:
-			s_endline(s, dosharp);
-			if(inlist){
-				prefix = "";
-				inlist = 0;
-			}
-			if(!inpara){
-				inpara = 1;
-				s = s_appendlist(s, "\n", sharp, nil);
-			}
-			break;
-
-		case Wbullet:
-			s_endline(s, dosharp);
-			if(!inlist)
-				inlist = 1;
-			if(inpara)
-				inpara = 0;
-			s = s_append(s, " *\t");
-			prefix = "\t";
-			break;
-
-		case Wlink:
-			if(inpara)
-				inpara = 0;
-			t = s_append(s_copy("["), w->text);
-			if(w->url == nil)
-				t = s_append(t, "]");
-			else{
-				t = s_append(t, " | ");
-				t = s_append(t, w->url);
-				t = s_append(t, "]");
-			}
-			s = s_appendbrk(s, s_to_c(t), prefix, dosharp);
-			s_free(t);
-			break;
-
-		case Wman:
-			if(inpara)
-				inpara = 0;
-			s = s_appendbrk(s, w->text, prefix, dosharp);
-			sprint(tmp, "(%d)", w->section);
-			s = s_appendbrk(s, tmp, prefix, dosharp);
-			break;
-
-		case Wpre:
-			if(inlist){
-				prefix = "";
-				inlist = 0;
-			}
-			if(inpara)
-				inpara = 0;
-			s_endline(s, dosharp);
-			s = s_appendlist(s, "! ", w->text, "\n", sharp, nil);
-			break;
-		case Whr:
-			s_endline(s, dosharp);
-			s = s_appendlist(s, "------------------------------------------------------ \n", sharp, nil);
-			break;
-
-		case Wplain:
-			if(inpara)
-				inpara = 0;
-			s = s_appendbrk(s, w->text, prefix, dosharp);
-			break;
-		}
-	}
-	s_endline(s, dosharp);
-	s->ptr--;
-	*s->ptr = '\0';
-	return s;
-}
-
-static String*
-historytext(String *s, Whist *h)
-{
-	int i;
-	char tmp[40];
-	char *atime;
-
-	for(i=h->ndoc-1; i>=0; i--){
-		if(i==h->current)
-			sprint(tmp, "[current]");
-		else
-			sprint(tmp, "[%lu/]", h->doc[i].time);
-		atime = ctime(h->doc[i].time);
-		atime[strlen(atime)-1] = '\0';
-		s = s_appendlist(s, " * ", tmp, " ", atime, nil);
-		if(h->doc[i].author)
-			s = s_appendlist(s, ", ", h->doc[i].author, nil);
-		if(h->doc[i].conflict)
-			s = s_append(s, ", conflicting write");
-		s = s_append(s, "\n");
-		if(h->doc[i].comment)
-			s = s_appendlist(s, "<i>", h->doc[i].comment, "</i>\n", nil);
-	}
-	return s;
-}
-
-String*
-totext(Whist *h, Wdoc *d, int ty)
-{
-	char *atime;
-	char *p, *q, ver[40];
-	int nsub;
-	Sub sub[3];
-	String *s, *t;
-
-	t = gettemplate(Ntemplate+ty);
-	if(p = strstr(s_to_c(t), "PAGE"))
-		q = p+4;
-	else{
-		p = s_to_c(t)+s_len(t);
-		q = nil;
-	}
-
-	nsub = 0;
-	if(h){
-		sub[nsub] = (Sub){ "TITLE", h->title };
-		nsub++;
-	}
-	if(d){
-		sprint(ver, "%lu", d->time);
-		sub[nsub] = (Sub){ "VERSION", ver };
-		nsub++;
-		atime = ctime(d->time);
-		atime[strlen(atime)-1] = '\0';
-		sub[nsub] = (Sub){ "DATE", atime };
-		nsub++;
-	}
-
-	s = s_reset(nil);
-	s = s_appendsub(s, s_to_c(t), p-s_to_c(t), sub, nsub);
-	switch(ty){
-	case Tpage:
-	case Toldpage:
-		s = pagetext(s, d->wtxt, 0);
-		break;
-	case Thistory:
-		s = historytext(s, h);
-		break;
-	case Tnew:
-	case Twerror:
-		break;
-	}
-	if(q)
-		s = s_appendsub(s, q, strlen(q), sub, nsub);
-	s_free(t);
-	return s;
-}
-
-String*
-doctext(String *s, Wdoc *d)
-{
-	char tmp[40];
-
-	sprint(tmp, "D%lu", d->time);
-	s = s_append(s, tmp);
-	if(d->comment){
-		s = s_append(s, "\nC");
-		s = s_append(s, d->comment);
-	}
-	if(d->author){
-		s = s_append(s, "\nA");
-		s = s_append(s, d->author);
-	}
-	if(d->conflict)
-		s = s_append(s, "\nX");
-	s = s_append(s, "\n");
-	s = pagetext(s, d->wtxt, 1);
-	return s;
-}

+ 0 - 141
sys/src/cmd/wikifs/util.c

@@ -1,141 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <ctype.h>
-#include <thread.h>
-#include "wiki.h"
-
-void*
-erealloc(void *v, uint32_t n)
-{
-	v = realloc(v, n);
-	if(v == nil)
-		sysfatal("out of memory reallocating %lu", n);
-	setmalloctag(v, getcallerpc());
-	return v;
-}
-
-void*
-emalloc(uint32_t n)
-{
-	void *v;
-
-	v = malloc(n);
-	if(v == nil)
-		sysfatal("out of memory allocating %lu", n);
-	memset(v, 0, n);
-	setmalloctag(v, getcallerpc(&n));
-	return v;
-}
-
-char*
-estrdup(char *s)
-{
-	int l;
-	char *t;
-
-	if (s == nil)
-		return nil;
-	l = strlen(s)+1;
-	t = emalloc(l);
-	memmove(t, s, l);
-	setmalloctag(t, getcallerpc(&s));
-	return t;
-}
-
-char*
-estrdupn(char *s, int n)
-{
-	int l;
-	char *t;
-
-	l = strlen(s);
-	if(l > n)
-		l = n;
-	t = emalloc(l+1);
-	memmove(t, s, l);
-	t[l] = '\0';
-	setmalloctag(t, getcallerpc(&s));
-	return t;
-}
-
-char*
-strlower(char *s)
-{
-	char *p;
-
-	for(p=s; *p; p++)
-		if('A' <= *p && *p <= 'Z')
-			*p += 'a'-'A';
-	return s;
-}
-
-String*
-s_appendsub(String *s, char *p, int n, Sub *sub, int nsub)
-{
-	int i, m;
-	char *q, *r, *ep;
-
-	ep = p+n;
-	while(p<ep){
-		q = ep;
-		m = -1;
-		for(i=0; i<nsub; i++){
-			if(sub[i].sub && (r = strstr(p, sub[i].match)) && r < q){
-				q = r;
-				m = i;
-			}
-		}
-		s = s_nappend(s, p, q-p);
-		p = q;
-		if(m >= 0){
-			s = s_append(s, sub[m].sub);
-			p += strlen(sub[m].match);
-		}
-	}
-	return s;
-}
-
-String*
-s_appendlist(String *s, ...)
-{
-	char *x;
-	va_list arg;
-
-	va_start(arg, s);
-	while(x = va_arg(arg, char*))
-		s = s_append(s, x);
-	va_end(arg);
-	return s;
-}
-
-int
-opentemp(char *template)
-{
-	int fd, i;
-	char *p;
-
-	p = estrdup(template);
-	fd = -1;
-	for(i=0; i<10; i++){
-		mktemp(p);
-		if(access(p, 0) < 0 && (fd=create(p, ORDWR|ORCLOSE, 0444)) >= 0)
-			break;
-		strcpy(p, template);
-	}
-	if(fd >= 0)
-		strcpy(template, p);
-	free(p);
-
-	return fd;
-}

+ 0 - 85
sys/src/cmd/wikifs/wdir.c

@@ -1,85 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-/* open, create relative to wiki dir */
-char *wikidir;
-
-static char*
-wname(char *s)
-{
-	char *t;
-
-	t = emalloc(strlen(wikidir)+1+strlen(s)+1);
-	strcpy(t, wikidir);
-	strcat(t, "/");
-	strcat(t, s);
-	return t;
-}
-
-int
-wopen(char *fn, int mode)
-{
-	int rv;
-
-	fn = wname(fn);
-	rv = open(fn, mode);
-	free(fn);
-	return rv;
-}
-
-int
-wcreate(char *fn, int mode, int32_t perm)
-{
-	int rv;
-
-	fn = wname(fn);
-	rv = create(fn, mode, perm);
-	free(fn);
-	return rv;
-}
-
-Biobuf*
-wBopen(char *fn, int mode)
-{
-	Biobuf *rv;
-
-	fn = wname(fn);
-	rv = Bopen(fn, mode);
-	free(fn);
-	return rv;
-}
-
-int
-waccess(char *fn, int mode)
-{
-	int rv;
-
-	fn = wname(fn);
-	rv = access(fn, mode);
-	free(fn);
-	return rv;
-}
-
-Dir*
-wdirstat(char *fn)
-{
-	Dir *d;
-
-	fn = wname(fn);
-	d = dirstat(fn);
-	free(fn);
-	return d;
-}

+ 0 - 130
sys/src/cmd/wikifs/wiki.h

@@ -1,130 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-typedef struct Map Map;
-typedef struct Mapel Mapel;
-typedef struct Sub Sub;
-typedef struct Wdoc Wdoc;
-typedef struct Whist Whist;
-typedef struct Wpage Wpage;
-
-enum {
-	Tcache = 5,	/* seconds */
-	Maxmap = 10*1024*1024,
-	Maxfile = 100*1024,
-};
-enum {
-	Wpara,
-	Wheading,
-	Wbullet,
-	Wlink,
-	Wman,
-	Wplain,
-	Wpre,
-	Whr,
-	Nwtxt,
-};
-
-struct Wpage {
-	int type;
-	char *text;
-	int section;	/* Wman */
-	char *url;		/* Wlink */
-	Wpage *next;
-};
-
-struct Whist {
-	Ref;
-	int n;
-	char *title;
-	Wdoc *doc;
-	int ndoc;
-	int current;
-};
-
-struct Wdoc {
-	char *author;
-	char *comment;
-	int conflict;
-	uint32_t time;
-	Wpage *wtxt;
-};
-
-enum {
-	Tpage,
-	Tedit,
-	Tdiff,
-	Thistory,
-	Tnew,
-	Toldpage,
-	Twerror,
-	Ntemplate,
-};
-
-struct Sub {
-	char *match;
-	char *sub;
-};
-
-struct Mapel {
-	char *s;
-	int n;
-};
-
-struct Map {
-	Ref;
-	Mapel *el;
-	int nel;
-	ulong t;
-	char *buf;
-	Qid qid;
-};
-
-void *erealloc(void*, uint32_t);
-void *emalloc(uint32_t);
-char *estrdup(char*);
-char *estrdupn(char*, int);
-char *strcondense(char*, int);
-char *strlower(char*);
-
-String *s_appendsub(String*, char*, int, Sub*, int);
-String *s_appendlist(String*, ...);
-Whist *Brdwhist(Biobuf*);
-Wpage *Brdpage(char*(*)(void*,int), void*);
-
-void printpage(Wpage*);
-String *pagehtml(String*, Wpage*, int);
-String *pagetext(String*, Wpage*, int);
-String *tohtml(Whist*, Wdoc*, int);
-String *totext(Whist*, Wdoc*, int);
-String *doctext(String*, Wdoc*);
-
-Whist *getcurrent(int);
-Whist *getcurrentbyname(char*);
-Whist *gethistory(int);
-void closewhist(Whist*);
-int allocnum(char*, int);
-void freepage(Wpage*);
-int nametonum(char*);
-char *numtoname(int);
-int writepage(int, uint32_t, String*, char*);
-void voidcache(int);
-
-void closemap(Map*);
-void currentmap(int);
-
-extern Map *map;
-extern RWLock maplock;
-extern char *wikidir;
-Biobuf *wBopen(char*, int);
-int wopen(char*, int);
-int wcreate(char*, int, long);
-int waccess(char*, int);
-Dir *wdirstat(char*);
-int opentemp(char*);

+ 0 - 76
sys/src/cmd/wikifs/wiki2html.c

@@ -1,76 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-char *wikidir;
-
-void
-usage(void)
-{
-	fprint(2, "usage: wiki2html [-hoDP ] [-d dir] wikifile\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	int t;
-	int parse;
-	String *h;
-	Whist *doc;
-
-	rfork(RFNAMEG);
-
-	t = Tpage;
-	ARGBEGIN{
-	default:
-		usage();
-	case 'd':
-		wikidir = EARGF(usage());
-		break;
-	case 'h':
-		t = Thistory;
-		break;
-	case 'o':
-		t = Toldpage;
-		break;
-	case 'D':
-		t = Tdiff;
-		break;
-	case 'P':
-		parse = 1;
-	}ARGEND
-
-	if(argc != 1)
-		usage();
-
-	if(t == Thistory || t==Tdiff)
-		doc = gethistory(atoi(argv[0]));
-	else
-		doc = getcurrent(atoi(argv[0]));
-
-	if(doc == nil)
-		sysfatal("doc: %r");
-
-	if(parse){
-		printpage(doc->doc->wtxt);
-		exits(0);
-	}
-	if((h = tohtml(doc, doc->doc+doc->ndoc-1, t)) == nil)
-		sysfatal("wiki2html: %r");
-
-	write(1, s_to_c(h), s_len(h));
-	exits(0);
-}

+ 0 - 59
sys/src/cmd/wikifs/wiki2text.c

@@ -1,59 +0,0 @@
-/*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <String.h>
-#include <thread.h>
-#include "wiki.h"
-
-char *wikidir = ".";
-
-void
-usage(void)
-{
-	fprint(2, "usage: wiki2text [-d dir] wikifile\n");
-	exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
-	int i;
-	Biobuf *b;
-	String *h;
-	Whist *doc;
-
-	ARGBEGIN{
-	default:
-		usage();
-	case 'd':
-		wikidir = EARGF(usage());
-		break;
-	}ARGEND
-
-	if(argc != 1)
-		usage();
-
-	if((b = Bopen(argv[0], OREAD)) == nil)
-		sysfatal("Bopen: %r");
-
-	if((doc = Brdwhist(b)) == nil)
-		sysfatal("Brdwtxt: %r");
-
-	h = nil;
-	for(i=0; i<doc->ndoc; i++){
-		print("__________________ %d ______________\n", i);
-		if((h = pagetext(s_reset(h), doc->doc[i].wtxt, 1)) == nil)
-			sysfatal("wiki2html: %r");
-		write(1, s_to_c(h), s_len(h));
-	}
-	exits(0);
-}