/*****************************************************************************/ /* 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-2021 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION HISTORY --------------- 13-MAY-2015 MGD v1.0.1, bugfix; closing and 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 #ifdef __x86_64 # define SOFTWAREID SOFTWARENM " X86-" SOFTWAREVN #endif /* standard C header files */ #include #include #include #include #include /* 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, "\n\ \n\ \n\ %s\n\ \n\ \n\ \n\ \n\
",
           cptr, SOFTWAREID);

   while (fgets (Line, sizeof(Line), fptr) != NULL)
   {
      LineCount++;
      if (LineCount <= 9999)
         cptr = "[%04.04d]\n";
      else
      if (LineCount <= 99999)
         cptr = "[%05.05d]\n";
      else
         cptr = "[%06.06d]\n";
      fprintf (stdout, cptr, LineCount, LineCount);
   }

   rewind (fptr);
   fputs ("
\n
", 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 ("
\n\n\n", stdout); fclose (fptr); } /*****************************************************************************/