[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244]
/*****************************************************************************/ /* liner.c Display a file as plain-text (actually escaped HTML), prefixing each line with an ascending line number in square brackets. The response does everything it can to ensure content is not cached so any repeat access should be just as expensive as the original :-) Two-pass formatting to allow cut-and-paste unencumbered by line numbers. Adding a hash fragment integer to the URL (e.g. "/liner.c#100") will cause the browser to move the window to that line number in the source (if it exists). Appending "$.txt" or "$.htm" to any file name (in fact "$.anythingatall") is allowed to try and get certain operating systems (whose name cannot be spoken) to treat the content as text (i.e. not using the returned content-type, rather the trailing three characters of the file name). If the supplied file name cannot be opened the utility removes any faux "$.extension" and attempts to open the resulting file name. Can be accessed using /cgi-bin/liner/path/to/file.txt or abbreviated using the WASD_CONFIG_MAP mapping rule script /liner/* /cgi-bin/liner* and used as /liner/path/to/file.txt A directory structure (e.g. source code tree) can have this mapping applied to all file accesses using the "?httpd=index" facility. For example /wasd_root/src/*.*?httpd=index&script=liner BUILD DETAILS ------------- $ @BUILD_LINER BUILD !compile+link $ @BUILD_LINER LINK !link-only COPYRIGHT --------- Copyright (C) 2013-2015 Mark G.Daniel This program, comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version. http://www.gnu.org/licenses/gpl.txt VERSION HISTORY --------------- 13-MAY-2015 MGD v1.0.1, bugfix; closing </body> and </html> 23-MAY-2013 MGD v1.0.0, initial (q&d) development */ /*****************************************************************************/ #define SOFTWAREVN "1.0.1" #define SOFTWARENM "LINER" #ifdef __ALPHA # define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN #endif #ifdef __ia64 # define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN #endif #ifdef __VAX # define SOFTWAREID SOFTWARENM " VAX-" SOFTWAREVN #endif /* standard C header files */ #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> /* CGILIB header file */ #include "cgilib.h" /* macros */ #define FI_LI __FILE__, __LINE__ /*****************************************************************************/ /* */ main (int argc, char** argv) { int LineCount = 0; char *aptr, *cptr, *sptr; char Line [1024], HtmlEnc [sizeof(Line)*6]; /* worst case */ FILE *fptr; /*********/ /* begin */ /*********/ CgiLibEnvironmentInit (argc, argv, 0); CgiLibResponseSetErrorMessage ("Reported by LINER"); if (strcmp (CgiLibVar ("REQUEST_METHOD"), "GET")) { CgiLibResponseSetErrorStatus (501); CgiLibResponseError (FI_LI, 0, "Only supports GET method!"); return; } aptr = CgiLibVar ("PATH_INFO"); if (!*aptr) { CgiLibResponseSetErrorStatus (501); CgiLibResponseError (FI_LI, 0, "Supply a file name!"); return; } sptr = CgiLibVar ("PATH_TRANSLATED"); if (!*sptr) { CgiLibResponseSetErrorStatus (501); CgiLibResponseError (FI_LI, 0, "PATH_TRANSLATED?"); return; } if ((fptr = fopen (sptr, "r", "shr=get")) == NULL) { for (cptr = sptr; *cptr; cptr++); while (cptr > sptr && *cptr != '$' && *cptr != ']') cptr--; if (*cptr == '$' && *(cptr+1) == '.') { /* chop these off and see if that opens */ *cptr-- = '\0'; while (cptr > sptr && *cptr != ']' && *cptr != '.' && *cptr != '$') cptr--; if (cptr > sptr && *cptr == '.') { if (cptr > sptr && *(cptr-1) == '^') { /* eliminate the EFS escape */ for (; *cptr; cptr++) *(cptr-1) = *cptr; *(cptr-1) = '\0'; } fptr = fopen (sptr, "r", "shr=get"); } else if (cptr > sptr && *cptr == '$') { /* non-EFS convert substituted dollar back to a period */ *cptr = '.'; fptr = fopen (sptr, "r", "shr=get"); } } if (fptr == NULL) { CgiLibResponseSetErrorStatus (404); CgiLibResponseError (FI_LI, vaxc$errno, aptr); return; } } if ((stdout = freopen ("SYS$OUTPUT", "w", stdout, "ctx=bin")) == NULL) exit (vaxc$errno); CgiLibResponseSetStreamMode (1); CgiLibResponseHeader (200, "text/html", "Expires: Fri, 13 Jan 1978 14:00:00 GMT\r\n\ Cache-Control: no-cache, no-store, private, max-age=0, max-stale=0, \ must-revalidate, pre-check=0, post-check=0\r\n\ Pragma: no-cache\r\n"); for (cptr = aptr; *cptr; cptr++); while (cptr > aptr && *cptr != '/') cptr--; if (*cptr == '/') cptr++; fprintf (stdout, "<!DOCTYPE html>\n\ <html>\n\ <head>\n\ <title>%s</title>\n\ <meta name=\"generator\" content=\"%s\">\n\ <style type=\"text/css\">\n\ body { color:black; background-color:white; }\n\ a { color:gray; }\n\ pre { display:block; margin:0; }\n\ .lnum { float:left; margin-right:1em; }\n\ </style>\n\ </head>\n\ <body>\n\ <pre class=\"lnum\">", cptr, SOFTWAREID); while (fgets (Line, sizeof(Line), fptr) != NULL) { LineCount++; if (LineCount <= 9999) cptr = "<a name=\"%d\">[%04.04d]</a>\n"; else if (LineCount <= 99999) cptr = "<a name=\"%d\">[%05.05d]</a>\n"; else cptr = "<a name=\"%d\">[%06.06d]</a>\n"; fprintf (stdout, cptr, LineCount, LineCount); } rewind (fptr); fputs ("</pre>\n<pre>", stdout); while (fgets (Line, sizeof(Line), fptr) != NULL) { sptr = HtmlEnc; for (cptr = Line; *cptr; cptr++) { switch (*cptr) { /* control characters with a bullet symbol */ case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 : case 7 : case 8 : case 11 : case 12 : case 14 : case 15 : case 16 : case 17 : case 18 : case 19 : case 20 : case 21 : case 22 : case 23 : case 24 : case 25 : case 26 : case 27 : case 28 : case 29 : case 30 : case 31 : *(unsigned long*)sptr = '&bul'; sptr += 4; *(unsigned short*)sptr = 'l;'; sptr += 2; break; /* HTML reserved */ case '<' : *(unsigned long*)sptr = '<'; sptr += 4; break; case '>' : *(unsigned long*)sptr = '>'; sptr += 4; break; case '&' : *(unsigned long*)sptr = '&'; sptr += 4; *sptr++ = ';'; break; /* the great unwashed */ default : *sptr++ = *cptr; } } *sptr = '\0'; fputs (HtmlEnc, stdout); } fputs ("</pre>\n</body>\n</html>\n", stdout); fclose (fptr); } /*****************************************************************************/