home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 361_02 / vu.c < prev   
Text File  |  1991-09-20  |  16KB  |  466 lines

  1.  
  2.  
  3. /* VU --> A File Viewer ala MORE w/ Search & Multi-File/Pipe Lists
  4.  *
  5.  * J.Ekwall 13 March, 1990
  6.  *
  7.  * Copyrighted to the Public Domain.  Unlimited Distribution Authorized.
  8.  *
  9.  * User Assumes All Risks/Liabilities.
  10.  *
  11.  */
  12.  
  13. #include <ctype.h>
  14. #include <dos.h>
  15. #include <gadgets.h>
  16. #include <io.h>
  17. #include <keys.h>
  18. #include <setjmp.h>
  19. #include <stdio.h>
  20. #include <stdek.h>
  21. #include <string.h>
  22.  
  23. char *Documentation[] = {
  24.     "",
  25.     "Usage:",
  26.     "       VU [options][drive:][path]filename [, ...] --> View Text Files.",
  27.     "     | VU [options] ---> View a Text Stream ala MORE.",
  28.     "",
  29.     "Options:",
  30.     "       /A -------------> Query for Initial Search.",
  31.     "       /B -------------> Build/ReBuild Select List.",
  32.     "       /C0xhhhhhh -----> Specify Colors.   [D:/C0x1F301E]",
  33.     "       /F \"FindMe\" ----> Jump to Text Match.",
  34.     "       /K -------------> Pop w/ Select List.",
  35.     "       /R -------------> Respect RamPage UnderLines.",
  36.     "       /S -------------> CGA Snow Protection.",
  37.     "",
  38.     "  Named Pipes are Legal.  Pipes are NOT Errased by Viewing.",
  39.     "",
  40.     "Last Updated: 18 September 91/EK",
  41.     "",
  42.     NULL};
  43.  
  44. char *Pop_Help[] = {
  45.     "  <ESC> ---------> Exit & View Next File <If Any>.",
  46.     " Alt-X ----------> Exit. (Don't View Next File).",
  47.     "  <Enter> -------> Pop Item Select List.  <If Any>",
  48.     " ^<Enter> -------> Build/ReBuild a Select List.",
  49.     "   F2 -----------> Find a Text Phrase.",
  50.     "Shift-F2 --------> Find a Text Phrase.  Ignore Case.",
  51.     "   F3 -----------> \"Fuzzy Logic\" Word Finder.",
  52.     "Shift-F3 --------> \"Fuzzy Logic\" Word Finder. Ignore Case.",
  53.     "   F4 -----------> Repeat Search.",
  54.     "   F5 -----------> Strip Hi-Bit Toggle.        [D:don't]",
  55.     "   F6 -----------> Respect RamPage UnderLines. [D:don't]",
  56.     "   F8 -----------> Set F3 \"Fuzz\" Level [D: 5]",
  57.     "   F9 -----------> Select Another File to View",
  58.     "   F10 ----------> Set/Report Color Settings.",
  59.     "",
  60.     "  <Home> / <Page Up>   / <Up Arrow> ----> Roll Upwards.",
  61.     "  <End>  / <Page Down> / <Down Arrow> --> Roll Downward.",
  62.     "  <Right/Left Arrow> --> Shift Text 10 Spaces.",
  63.     "",
  64.     "  Any Other Key -> Roll Down 11 Lines (Half a Screen).",
  65.     NULL};
  66.  
  67.  
  68. char *Pop_Help2[] = {
  69.     "   \"Fuzzy Find\" use the Levenstein Distance Algorithm to",
  70.     "compute a \"FuzzFactor\" (how well what you got matches",
  71.     "what you wanted):",
  72.     "",
  73.     "        Wanted       Have     FuzzFactor",
  74.     "        ──────       ────     ──────────",
  75.     "        FooBar  -->  FooBar ----> 0",
  76.     "        FooBar  -->  fooBar ----> 1",
  77.     "        FooBar  -->  FooxBar ---> 1",
  78.     "        Foo     -->  FooBar ----> 3",
  79.     "        Bar     -->  FooBar ----> 3",
  80.     "        FooBar  -->  FooBat ----> 3",
  81.     "        FooBar  -->  FooBa -----> 7",
  82.     "        FooBar  -->  FoBar -----> 9",
  83.     "        FooBar  -->  Foo -------> 20",
  84.     "",
  85.     "   The Value You Set Determines What will be a \"Match\".",
  86.     NULL};
  87.  
  88. /* Declare Constants */
  89. #define LINESIZE    513
  90.  
  91. /* Declare Globale */
  92. BYTE BarColor = 0x30, NmlColor = 0x1F, HiLite = 0x1E;
  93. int CrashStop = FALSE, WordStar = FALSE, InitAsk = FALSE, InitLst = FALSE;
  94. int Offset = 0, ReBuild = FALSE, Fuzz = 5, RamPage = FALSE, Cleanup = FALSE;
  95. BYTE Find[81], Line[LINESIZE], Name[81], Text[LINESIZE], LastFind[81];
  96. FILE *fp = stdin;
  97.  
  98. /* Declare Local ProtoTypes */
  99. int  AtoHexColors(char **ptr);
  100. int  FindLine(int Start, int CaseLess);
  101. int  FuzzyFind(char *Have, char *Want);
  102. void GrabStdin(void);
  103. int  ItemList(void);
  104. void PaintCRT(int TopLine);
  105. void Show(int CaseLess);
  106. void Usage(void);
  107. void UserSetsColors(void);
  108.  
  109. main (int argc, char *argv[])
  110. {
  111.     int i, xx, yy, Flag = FALSE;
  112.     char *tp1, FootPrint[4000];
  113.  
  114.  /* Set Option Flags */
  115.     *Find = *LastFind = NULL;
  116.     while (*argv[1] IS SLASH) {
  117.        for (tp1 = argv[1] + 1; *tp1 != NULL; ) {
  118.       switch (toupper(*tp1++)) {
  119.       case 'A': InitAsk++; break;
  120.       case 'B': ReBuild++; break;
  121.           case 'C':             /* Colors */
  122.          if (!AtoHexColors(&tp1)) Usage(); break;
  123.           case 'F':
  124.              if (argc IS 2) Usage();
  125.              for (i = 1, --argc; i < argc + 1; i++) argv[i] = argv[i+1];
  126.              strcpy(Find,argv[1]); strupr(Find); Flag = TRUE;
  127.              break;
  128.       case 'K': InitLst++; break;
  129.       case 'S': CgaSnowFence(); break;
  130.           default:
  131.              fprintf(stderr,"\nInvalid Option [/%c].\n\n",*tp1);
  132.              Usage();
  133.           }
  134.        }
  135.  
  136.     /* SHIFT */
  137.        for (i = 1, --argc; i < argc + 1; i++) argv[i] = argv[i+1];
  138.     }
  139.  
  140.  /* Save FootPrint Area */
  141.     Getxy(&xx, &yy); SaveBox(1, 1, 80, 25, FootPrint); HideCursor();
  142.  
  143.  /* Determine Ops Mode */
  144.     if (argc IS 1)  {                    /* Barefoot Mode */
  145.        if (INFLOW_EXISTS) GrabStdin();
  146.        if (FileExists("\\STD OUT")) strcpy(Name,"\\STD OUT");
  147.        else if (FileExists("\\STD IN"))  strcpy(Name,"\\STD IN");
  148.        else Usage();
  149.        Show(Flag); argc--;
  150.     }
  151.  
  152.  /* Show the Specified Files */
  153.     for (i = 1; i < argc; i++) {
  154.        if (*argv[i] IS '$') {
  155.           strcpy(Name,"\\STD "); strcat(Name,++argv[i]);
  156.        } else strcpy(Name,argv[i]);
  157.        if (FileExists(Name)) Show(Flag);
  158.        Flag = FALSE; GetLineN(NULL, 0); if (CrashStop) break;
  159.     }
  160.  
  161.  /* Restore FootPrint & Split */
  162.     RestoreBox(1, 1, 80, 25, FootPrint); Gotoxy(xx, yy); ShowCursor(0);
  163.     if (Cleanup) unlink("\\STD IN"); exit(0);
  164. }
  165.  
  166. int AtoHexColors(char **ptr)
  167. {
  168.     int c, i = 0;
  169.     unsigned int n = 0;
  170.  
  171.     if (strncmp(*ptr, "0x", 2) && strncmp(*ptr, "0X", 2)) return FALSE;
  172.     for (*ptr += 2; isxdigit(c = toupper(**ptr)) && i++ < 6; *ptr += 1) {
  173.     n = (isdigit(c)) ? 16 * n + c - 48 : 16 * n + c - 55;
  174.     if (i IS 2) { NmlColor = n; n = 0; }
  175.     if (i IS 4) { BarColor = n; n = 0; }
  176.     if (i IS 6) HiLite = n;
  177.     }
  178.     return (i >= 6);
  179. }
  180.  
  181. int FindLine(int Start, int CaseLess)
  182. {
  183.     int i, Dits = 18;
  184.     char *tp1, DitLine[81];
  185.  
  186.     if (!*Find) return(Start); strcpy(DitLine, "---<Scanning>--- ");
  187.     strcpy(LastFind, Find);
  188.     for (i = Start; GetLineN(Line, (++i) + 1); ) {
  189.        if (WordStar) for (tp1 = Line; *tp1 != NULL; ) *tp1++ &= 127;
  190.        if (CaseLess % 2) strupr(Line);
  191.        if (CaseLess < 2) { if(strstr(Line, Find) != NULL) return(i); }
  192.        else for (tp1 = strtok(Line, " \t\n"); *tp1;
  193.       tp1 = strtok(NULL, " \t\n")) if (FuzzyFind(tp1, Find) < Fuzz)
  194.              return(i);
  195.        if (i % 23) continue;
  196.        if (++Dits IS 78) {
  197.           strcpy(DitLine,"."); Dits = 1;
  198.        } else strcat(DitLine, ".");
  199.        DwriteEnd(1, 25, BarColor, DitLine, 80);
  200.        if (Kbq_poll() IS SPACE) break;
  201.     }
  202.     putchar(BEL); return(Start);
  203. }
  204.  
  205. int FuzzyFind(char *Have, char *Want)
  206. {
  207.     int i, j, Delta, Prev, Distance[21];
  208.     char Text[21], String[21], *tp1, *tp2;
  209.  
  210.     strncpy(Text, Want, 20); strncpy(String, Have, 20);
  211.     Text[21] = String[21] = NULL; if (!*Want) return 0;
  212.     if (!*Have) return 5 * strlen(Want);
  213.     for (i = 0; i < 21; i++) Distance[i] = i;
  214.     tp1 = Text;
  215.     do {
  216.        Prev = Distance[0] + 5; tp2 = String; i = 0;
  217.        do {
  218.           Delta = Prev + 1;
  219.           if (*tp1 == *tp2) j = 0;
  220.       else if (toupper(*tp1) == toupper(*tp2)) j = 1;
  221.           else j = 3;
  222.       if ((j += Distance[i]) < Delta) Delta = j; Distance[i] = Prev;
  223.       if ((j = Distance[++i] + 5) < Delta) Delta = j; Prev = Delta;
  224.        } while (*tp2++);
  225.        Distance[strlen(String)] = Delta;
  226.     } while (*tp1++);
  227.     if ((j = strlen(Text) - strlen(String)) > 0) Delta += 4 * j;
  228.     return --Delta;
  229. }
  230.  
  231. void GrabStdin(void)
  232. {
  233.     int c;
  234.  
  235.     if ((fp = fopen("\\STD IN", "w")) IS NULL) Usage();
  236.     while((c = getchar()) != EOF) fputc(c, fp);
  237.     fclose(fp); Cleanup++;
  238. }
  239.  
  240. int ItemList(void)
  241. {
  242.  /* Find/Read .LST File, Present List(s) & Post User Selection */
  243.     int i, Flag, TopItem, NxtLine, X, Y, xx, yy;
  244.     char ListName[81], *tp1;
  245.  
  246.  /* Find .LST File */
  247.     strupr(Name); if (strstr(Name, ".TXT") IS NULL) return FALSE;
  248.     NewExt(Name, ListName, "LST");
  249.     if (ReBuild) {
  250.        if ((fp = fopen(ListName, "w")) IS NULL) return FALSE;
  251.        Clr(0); printf("Rebuilding Select List.  Please Wait.. ");
  252.        for (i = 1; GetLineN(Text, i++); ) {
  253.           if (*Text != '>') continue;
  254.       if ((tp1 = strstr(Text, ".  ")) != NULL) tp1[1] = NULL;
  255.           fprintf(fp, "%s\n", Text + 1);
  256.        }
  257.        fclose(fp); ReBuild = FALSE;
  258.     }
  259.     if (!FileExists(ListName)) return FALSE; GetLineN(ListName, 0);
  260.  
  261.  /* Construct Window */
  262.     strcpy(Text, "[ <Enter> to Select Item or <ESC> to Cancel ]");
  263.     PadEnds(Text, '─', 80); Dwrite(1, 1, BarColor, Text);
  264.  
  265.  /* Do Business */
  266.     TopItem = NxtLine = 0; ShowCursor(1); X = Y = 2;
  267. RePaint:
  268.     ClrBox(1, 2, 80, 24, 0x0E);
  269.     for (NxtLine = TopItem, xx = 3, Flag = TRUE; xx < 75 && Flag; xx += 20) {
  270.        for (yy = 2; Flag && yy < 25; yy++) {
  271.       Flag = GetLineN(Text, ++NxtLine); Text[17] = NULL;
  272.       Dwrite(xx, yy, 0x0A, Text);
  273.        }
  274.     }
  275.  
  276.  /* Update Footer */
  277.     if (Flag) sprintf(Text,"───────[ -MORE-  %c  %c ]",ESC,SUB);
  278.     else sprintf(Text,"───────[         %c  %c ]",ESC,SUB);
  279.     PadRight(Text, '─', 80); Dwrite(1, 25, BarColor, Text);
  280.  
  281.  /* Set Cursor & Get User Input */
  282.     for (Flag = FALSE; !Flag; ) {
  283.        Gotoxy(X, Y);
  284.        switch (Kbq_read()) {
  285.        case UP:   if (Y > 2) Y--; break;
  286.        case DN:   if (Y < 24) Y++; break;
  287.        case FWD:
  288.       if ((X += 20) < 75) break; else X -= 20; TopItem += 23; goto RePaint;
  289.        case BWD:
  290.       if (X > 2) { X -= 20; break; }
  291.           TopItem -= 23; if (TopItem < 0) TopItem = 0; goto RePaint;
  292.        case HOME:  X = Y = 2; break;
  293.        case END:   Y = 24; X = 62; break;
  294.        case PGUP:
  295.           X = Y = 2; TopItem -= 92; if (TopItem < 0) TopItem = 0;
  296.           goto RePaint;
  297.        case PGDN:
  298.           X = Y = 2; TopItem += 92; goto RePaint;
  299.        case ESC:  *Find = NULL; goto Tilt;
  300.        case CR:   /* Select */
  301.       *Find = '>';
  302.       Flag = GetLineN(Find+1, TopItem + (X / 20) * 23 + Y - 1);
  303.       if (Flag) Dwrite(X-1, Y, 0x0E, "-");
  304.        }
  305.     }
  306.  
  307.  /* Post Selection (If Any), Delete Window & Split */
  308. Tilt:
  309.     GetLineN(Name, 0); HideCursor(); return Flag;
  310. }
  311.  
  312. void PaintCRT(int TopLine)
  313. {
  314.     int c, i, Flag, Toggle, X;
  315.     char *tp1;
  316.  
  317.  /* Do Header Bar */
  318.     sprintf(Text, "[ VU File: %s ]", Name); PadEnds(Text, '═', 80);
  319.     Dwrite(1, 1, BarColor, Text);
  320.  
  321.  /* Paint In the Text Window */
  322.     for (i = 2; i < 25; i++) {
  323.        Flag = !GetLineN(Line, TopLine+i-1);
  324.        if (WordStar IS 1) for (tp1 = Line; *tp1 != NULL; ) *tp1++ &= 127;
  325.        if (strchr(Line, TAB) != NULL) ExpandTabs(Line);
  326.        if (RamPage && Tally(Line, UNDER)) {
  327.           Gotoxy(1, i);
  328.           for (X = -Offset, Toggle = 0, tp1 = Line; X < 80; ) {
  329.              if (*tp1) c = *tp1++; else c = SPACE;
  330.              if (c IS UNDER) { Toggle = !Toggle; continue; } 
  331.              if (++X < 1) continue; if (c IS BAR) c = '│';
  332.              if (!Toggle) DputChr(c, NmlColor);
  333.              else { if (c IS SPACE) c = UNDER; DputChr(c, HiLite); }
  334.           }
  335.        } else {
  336.           if (Offset >= strlen(Line)) *Text = NULL; 
  337.           else strncpy(Text, Line+Offset, 80); Text[80] = NULL;
  338.           if (strlen(Text) > 79 && Text[79]) Text[79] = BEL;
  339.           else PadRight(Text, SPACE, 80);
  340.           Dwrite(1, i, NmlColor, Text);
  341.        }
  342.     }
  343.  
  344.  /* Do Footer Bar */
  345.     if (!Flag)
  346.        sprintf(Text,"───[ -More- ]─────[ Lines %d : %d ]", TopLine+1, 
  347.           TopLine+23);
  348.     else sprintf(Text,"───[ *EOF* ]─────[ Lines %d : EOF ]", TopLine+1);
  349.     PadRight(Text, '─', 80); Dwrite(1, 25, BarColor, Text);
  350. }
  351.  
  352. void Show(int FindFlag)
  353. {
  354.  /* Show an ASCII File */
  355.     int TopLine = 0;
  356.     char CurrentName[81];
  357.  
  358.  /* Initialize & Do Initial Search */
  359.     Clr(NmlColor); GetLineN(Name, 0);
  360.     if (FindFlag) TopLine = FindLine(0, FindFlag); else *Find = NULL;
  361.     if (InitLst) {
  362.        InitLst = FALSE; if (ItemList()) TopLine = FindLine(0, FALSE); }
  363.     if (InitAsk) {
  364.        InitAsk = FALSE;
  365.        if (Query(Find, "[ Enter Text to Find.  F2 = Any Character. ]", 
  366.           FindFlag, 0x4F, Pop_Help)) TopLine = FindLine(0, FALSE);
  367.     }
  368.     HideCursor(); PaintCRT(TopLine);
  369.  
  370.  /* Show Text ala more */
  371.     for (EVER) {
  372.  
  373.     /* Query User */
  374.  
  375.        switch (Kbq_read()) {
  376.        case END:   while(GetLineN(Line, 24 + TopLine++)); break;
  377.        case PGDN:  TopLine += 22; break;
  378.        case LF:    ReBuild++;
  379.        case CR:    if (ItemList()) TopLine = FindLine(0, FALSE); break;
  380.        case DN:    TopLine += 1; break;
  381.        case HOME:  TopLine = 0; break;
  382.        case PGUP:  TopLine -= 21;
  383.        case UP:    TopLine -= 1; if (TopLine < 0) TopLine = 0; break;
  384.        case ALT_X: CrashStop = TRUE;
  385.        case ESC:   fclose(fp); return;      /* Clean Up & Exit */
  386.        case BWD:   Offset += 20;
  387.        case FWD:   Offset = (Offset > 10) ? Offset-10 : 0; break;
  388.        case F1:    PopHelp(Pop_Help); continue;
  389.        case F2:       FindFlag = 9;
  390.        case SHIFT_F2: if (FindFlag < 5) FindFlag = 10;
  391.        case F3:       if (FindFlag < 5) FindFlag = 20;
  392.        case SHIFT_F3: if (FindFlag < 5) FindFlag = 30;
  393.           if (FindFlag > 5) FindFlag /= 10;
  394.       if (FindFlag < 2 && !Query(LastFind, 
  395.          "[ Enter Text to Find.  F2 = Any Character. ]", FindFlag, 0x4F, 
  396.          Pop_Help)) continue;
  397.       if (FindFlag > 1 && !Query(LastFind, 
  398.          "[ Enter Word to Find.  F2 = Any Character. ]", FindFlag%2, 0x4F, 
  399.             Pop_Help)) continue;
  400.        case F4:
  401.           strcpy(Find, LastFind); TopLine = FindLine(TopLine, FindFlag);
  402.           break;
  403.        case F5:  WordStar = !WordStar;  break;
  404.        case F6:  RamPage = !RamPage;  break;
  405.        case F8:
  406.           sprintf(Text, "%d", Fuzz);
  407.           if (!Query(Text, "[ Enter FuzzFactor Threshold: ]", 2, 0x4F,
  408.              Pop_Help2)) continue;
  409.       if ((Fuzz = atoi(Text)) < 2) Fuzz = 5; break;
  410.        case F9:
  411.           strcpy(CurrentName, Name);
  412.       if (Query(Name, "[ Enter File Name: ]", -2, 0x4E, Pop_Help)) {
  413.          if (FileExists(Name)) {
  414.                 GetLineN(Name, 0); Show(0); if (CrashStop) return; }
  415.          strcpy(Name, CurrentName); GetLineN(Name, 0);
  416.           }
  417.           break;
  418.        case F10:       UserSetsColors(); break;
  419.        default: TopLine += 11;
  420.        }
  421.        HideCursor(); PaintCRT(TopLine);
  422.     }
  423. }
  424.  
  425. void Usage(void)
  426. {
  427.     char   **dp = Documentation;
  428.  
  429.     for ( ; *dp; dp++) fprintf(stderr,"%s\n", *dp);
  430.     exit(1);
  431. }
  432.  
  433. void UserSetsColors(void)
  434. {
  435.     int i;
  436.  
  437.     strcpy(Text, "[ Set/Report_Current_Screen_Colors. ]");
  438.     PadEnds(Text, UNDER, 80); Dwrite(1, 1, HiLite, Text);
  439.     Dwrite(1, 25, BarColor,
  440. "Text: Left/Right.  Bars:Up/Down. UnderLined_Text: ^Left/Right.  <Esc> Exits."
  441. );
  442.     for (EVER) {
  443.  
  444.     /* Query User */
  445.        switch (Kbq_read()) {
  446.        case ESC:
  447.       sprintf(Text, "[ Current Color Setting: /C0x%02X%02X%02X ]",
  448.          NmlColor, BarColor, HiLite);
  449.       PadEnds(Text, 196, 80); Dwrite(1, 1, 0x4E,Text);
  450.       strcpy(Text, "[ Hit Any Key]");
  451.       PadEnds(Text, 196, 80); Dwrite(1, 25, 0x4E, Text);
  452.       Kbq_read(); return;
  453.        case FWD: NmlColor = (NmlColor & 0x70) + ((NmlColor+1) % 16); break;
  454.        case UP:  BarColor = (BarColor & 0x70) + ((BarColor+1) % 16); break;
  455.        case DN:  BarColor = (BarColor + 0x10) % 0x80; break;
  456.        case BWD: NmlColor = (NmlColor + 0x10) % 0x80; break;
  457.        case CTL_FWD:
  458.        HiLite = (HiLite & 0x70) + ((HiLite+1) % 16); break;
  459.        case CTL_BWD: HiLite = (HiLite + 0x10) % 0x80; break;
  460.        }
  461.        for (i = 2; i < 25; i++) RcolorSet(1, i, NmlColor, 80);
  462.        RcolorSet(1, 1, HiLite, 80); RcolorSet(1, 25, BarColor, 80);
  463.     }
  464. }
  465.  
  466.