home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 26 / CD_ASCQ_26_1295.iso / vrac / user_int.zip / READ.CPP < prev    next >
Text File  |  1995-08-28  |  49KB  |  1,531 lines

  1. #include <dir.h> // for directory operations //
  2. #include <dirent.h> // for directory operations //
  3. #include <fcntl.h> // for return value of drive ready test //
  4. #include <alloc.h> // for coreleft() memory testing //
  5. #include <ctype.h> // for toupper() //
  6. #include "mhandler.cpp"  // for mouse support //
  7. #include "window.cpp" // for windowing class //
  8. #include "scroll.cpp" // for scrolling screen up and down //
  9. #include "qprintf.cpp" // for quick screen output //
  10.  
  11. #define NUL '\0' // to null terminate strings //
  12. #define LAST_CHAR(str) (str)[strlen(str) - 1] // to chop a string by one //
  13.  
  14. void end(void);
  15. void read(void);
  16. void home(void);
  17. int getkey(void);
  18. void search(void);
  19. void page_up(void);
  20. void arrow_up(void);
  21. void new_file(void);
  22. void jump_read(void);
  23. void page_down(void);
  24. void scrollbar(void);
  25. void read_help(void);
  26. int cd(char *cdname);
  27. void arrow_down(void);
  28. void arrow_left(void);
  29. void arrow_right(void);
  30. void show_status(void);
  31. void file_select(void);
  32. void pause_win(char *s);
  33. int error_win(char *msg);
  34. void scroll_show(char *string);
  35. void scroll_select(int numelements);
  36. void show(int x, int y, char *string);
  37. int sort_function( const void *a, const void *b);
  38. void far handler(unsigned deverr, unsigned errval, unsigned far *devhdr);
  39.  
  40.    FILE *in; // file pointer //
  41.    unsigned long far *loc; // far array of dynamically allocated newline locations //
  42.    long searchloc, saveloc, lineloc; // search position trackers //
  43.    int sortorder=0; // for sorting by name(0), or extension(1) //
  44.    int i, z, bc, fc, cnt, mcnt, col=0, key, save, fail, startcnt, newscan; // control integers //
  45.    int num, searchsuccess, searched, lincount, lastline, maxsize, right, nofile=0, rightarray[25]; // control integers //
  46.    unsigned int ypos; // scroll bar position //
  47.    union REGS regs; // to hold dos function call registers //
  48.    char ch, tmp[3], linecount[25]; // storage for strings //
  49.    char filename[15], searchstring[50], showstring[50]; // storage for strings //
  50.    char **array; // array to store char pointers to filenames //
  51.    // reading window descriptor //
  52.    wintype w1(0, 0, 80, 25, 1, " ESC=Exit      F1=Help  F2=Search  F10=New  Home  End  PgUp  PgDn         ");
  53.    // help window descriptor //
  54.    wintype help(0, 0, 80, 25, 1, "    ESC=Resume                                          READ File Viewer    ");
  55.    // file selector window descriptor //
  56.    wintype scrollwin(31, 2, 49, 22, 1, "");
  57.    // wait window descriptor //
  58.    wintype pause(13, 7, 67, 9, 1, "");
  59.  
  60.    static char *err_msg[] = // standard error list //
  61.    { "Write protect",    "Unknown unit",
  62.      "Drive not ready",  "Unknown command",
  63.      "Data error (CRC)", "Bad request",
  64.      "Seek error",       "Unknown media type",
  65.      "Sector not found", "Printer out of paper",
  66.      "Write fault",      "Read fault",
  67.      "General failure",  "Reserved",
  68.      "Reserved",         "Invalid disk change"
  69.     };
  70.  
  71. int getkey(void)
  72. {
  73.    // implement delay rate if button still pressed from last call //
  74.    while(L_DOWN || R_DOWN) // if pressing either button //
  75.    { Mshow(); // keep showing mouse //
  76.      if(mcnt == 350) // 350 ms is a good mouse delay rate //
  77.      break; // break loop //
  78.      delay(1); // delay 1ms for each mcnt while either button is pressed //
  79.      mcnt++; // increment counter //
  80.     }
  81.    // once released reset mcnt to zero //
  82.    if(!L_DOWN && !R_DOWN) // if not pressing either button //
  83.    { mcnt=0; // reset counter if not pressed //
  84.     }
  85.    // begin waiting for mouse press or keyboard hit //
  86.    while(!kbhit()) // while the keyboard is not pressed //
  87.    { Mshow(); // keep showing mouse //
  88.      if(L_DOWN) // if left button pressed //
  89.      { Mhide(); // always hide mouse while screen changes //
  90.        delay(20); // 20ms is very close to most keyboard repeat rates //
  91.        return 999; // return 999, to use as a case in a switch statement. //
  92.       }      // After getkey() funtion returns back to where it came from //
  93.          // determine action based upon mouse M_xpos and M_ypos locations //
  94.      if(R_DOWN) // if right button pressed //
  95.      { Mhide(); // always hide mouse while screen changes //
  96.        delay(20); // 20ms is very close to most keyboard repeat rates //
  97.        return 1000; // return 1000, to use as case in a switch statement. //
  98.       }      // After getkey() funtion returns back to where it came from //
  99.     }         // determine action based upon mouse M_xpos and M_ypos locations //
  100.    // if it makes it to here, then the keyboard was just pressed //
  101.    Mhide(); // always hide mouse while screen changes //
  102.    // determine value of the key pressed above //
  103.    switch (key = (int)getch()) // get the key //
  104.    { case 0: return 256 + (int)getch(); // return 256 + extended key value //
  105.      default: return key; // return normal key value //
  106.     }
  107.  }
  108. void read(void) // function to read and display next line from the file //
  109. {
  110.    int l, xl, yl, cc=0; // control integers //
  111.  
  112.    fseek(in, loc[cnt], SEEK_SET); // seek to correct location for request //
  113.    yl=w1.gety(); // store y window location
  114.    do
  115.    { ch = fgetc(in); // get char from file //
  116.      if(ch == '\n')
  117.      { w1.resetxy();
  118.        cnt++;
  119.        cc=0;
  120.        right=0;
  121.        break;
  122.       }
  123.      if(ch == '\r')
  124.      { continue;
  125.       }
  126.      if(ch == '\t') // if tab //
  127.      { if(cc >= col) // if in viewport area //
  128.        { for(l=1;l<=8;l++) // expand it //
  129.      { xl=w1.getx(); // get x location for window //
  130.        qputch(xl+2,yl+2,7,' '); // fast display at correct location //
  131.        w1.movex(); // update cursor position //
  132.        cc++; // count spaces //
  133.       }
  134.     }
  135.        else // if not in viewport area //
  136.        { for(l=1;l<=8;l++)
  137.      { cc++; // just count the spaces //
  138.       }
  139.     }
  140.       }
  141.      else // skip returns, newlines and tabs and non-ascii //
  142.      { if(cc >= col) // if in viewport area //
  143.        { xl=w1.getx(); // get x location //
  144.      if(searchsuccess==1)
  145.      { if(ftell(in) >= searchloc && ftell(in) <= searchloc+strlen(searchstring)-1)
  146.        { if(vmode==3)
  147.          qputch(xl+2,yl+2,15+(1<<4),ch); // fast display at correct location //
  148.          else
  149.          qputch(xl+2,yl+2,0+(7<<4),ch); // fast display at correct location //
  150.         }
  151.        else
  152.        qputch(xl+2,yl+2,7,ch); // fast display at correct location //
  153.       }
  154.      else
  155.      qputch(xl+2,yl+2,7,ch); // fast display at correct location //
  156.      w1.movex(); // update cursor position //
  157.     }
  158.        cc++;
  159.       }
  160.      if(w1.getx() == 78) // if right margin //
  161.      { w1.resetxy(); // return to left margin //
  162.        cnt++; // advance linecount //
  163.        right=1; // fill right array with yes //
  164.        return;
  165.       }
  166.     } while(ch != EOF);  // while not done //
  167.    if(ch==EOF && cc==1) // adjust for EOF //
  168.    { cnt++;
  169.     }
  170.  }
  171. void jump_read(void) // jump to dragged scroll bar location and display //
  172. {
  173.    unsigned long x, y; // control integers //
  174.  
  175.    if(lastline<=23)
  176.    { show_status();
  177.      return;
  178.     }
  179.  
  180.    x = (ypos * 100) / 23; // percentage of scrollbar //
  181.    y = (x * (unsigned long)lastline) / 100; // line equiv of percentage //
  182.  
  183.    cnt = startcnt = y; // count = line //
  184.  
  185.    if(cnt>lastline-23)
  186.    cnt=startcnt=lastline-23;
  187.  
  188.    w1.wincls();
  189.    for(i=1; i<=23; i++)
  190.    { right=0;
  191.      read(); // regular read function //
  192.      if(ch == EOF)
  193.      { for(z=i;z<=23;z++)
  194.        rightarray[z]=0;
  195.        break;
  196.       }
  197.      if(right==1)
  198.      rightarray[i]=1;
  199.      else
  200.      rightarray[i]=0;
  201.     }
  202.    show_status();
  203.  }
  204. void show(int x, int y, char *string)
  205. {
  206.    w1.setcolor(fc); // set to foreground of border //
  207.    w1.setbkcolor(bc); // set to background of border //
  208.    w1.wcout(x, y, string); // write string //
  209.    w1.setcolor(white); // reset viewport foreground to white //
  210.    w1.setbkcolor(black); // reset viewport background to black //
  211.  }
  212. void scroll_show(char *string)
  213. {
  214.    scrollwin.setcolor(fc); // set to foreground of border //
  215.    scrollwin.setbkcolor(bc); // set to background of border //
  216.    scrollwin << string; // write string //
  217.    scrollwin.setcolor(lightgray); // reset viewport foreground to black //
  218.    scrollwin.setbkcolor(black); // reset viewport background to black //
  219.  }
  220. void pause_win(char *s)
  221. {
  222.    pause.setcolor(white);
  223.    if(vmode==3) pause.setbkcolor(blue); else pause.setbkcolor(black);
  224.    pause.winput(); pause.wincls();
  225.    pause.line_border();
  226.    pause << s;
  227.  }
  228. void show_status(void)
  229. {
  230.    int x; // x location integer //
  231.  
  232.    show(34,25,"        "); // clear area of lower border //
  233.    sprintf(showstring, "Column:  %d", col); // concatenate column string //
  234.    show(26,25,showstring); // show columns in lower border //
  235.    if(ch==EOF)cnt=lastline; // adjust for EOF //
  236.    sprintf(linecount,"Line:  %d of %d  ", cnt, lastline); // concat status //
  237.    x = (80-strlen(linecount)); // calculate x location for status //
  238.    show(57,25,"                         "); // ensure lower border is clear //
  239.    show(x+1,25,linecount); // show lines in lower border //
  240.    scrollbar(); // display right scrollbar //
  241.  }
  242. void scrollbar(void) // draw right scrollbar and location indicator //
  243. {
  244.    int y; // scroll bar position tracker //
  245.    unsigned long percent; // percentage of file tracker //
  246.    unsigned long x, m, curline, maxline; // used to calculate percentage //
  247.  
  248.    m = 23; // max scroll bar positions //
  249.    curline = cnt; // save cnt as an unsigned long for later use //
  250.    maxline = lastline; // save lastline as an unsigned long for later use //
  251.    _wscroll=0; // turn off screen scroll for bottom corner arrow //
  252.    for(y=1; y<=25; y++)  // display scroll bar loop //
  253.    { if(y==1) show(80,y,""); // if start of bar than show up arrow //
  254.      else if(y==25) show(80,y,""); // if end of bar than show down arrow //
  255.      else show(80,y,"░"); // show rest of scroll bar //
  256.     }
  257.   _wscroll=1; // reset screen scroll //
  258.   x = curline * m; // percentage of scroll bar //
  259.   ypos = x / maxline; // calculate new y position //
  260.   if(ypos==0) ypos=1; // if calculation is zero than yposition = 1;
  261.   show(80,ypos+1,""); // display file position indicator //
  262.   percent = (curline * 100) / maxline; // calculate percentage of file //
  263.   show(52,25,"     "); // clear lower border for status //
  264.   sprintf(showstring, "Percent:  %d", percent); // concat percentage //
  265.   show(43,25,showstring); // show percentage in lower border //
  266.  }
  267. void search(void)
  268. {
  269.    int a, count;
  270.    char alpha[3];
  271.    char buffer[255];
  272.    char *found;
  273.    wintype srch(19, 7, 59, 10, 1, "");
  274.  
  275.    searchsuccess=0;
  276.    if(vmode==3){ srch.setcolor(white); srch.setbkcolor(blue); }
  277.    else { srch.setcolor(black);srch.setbkcolor(lightgray); }
  278.    srch.winput(); srch.line_border();
  279.    srch.wcout(2,1," ESC ");
  280.    srch.wcout(12,1," Enter Text to Find ");
  281.    if(searched==1)
  282.    srch.wcout(9,4," F3 = Repeat Last Search ");
  283.    reenter : srch.wincls();
  284.    _setcursortype(_NORMALCURSOR);
  285.    srch << "\n  ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ";
  286.    srch.winxy(srch.getx()-36,srch.gety());
  287.  
  288.    count=0;
  289.    rekey : key = getkey();
  290.    if(key==317 && searched==1)
  291.    goto repeat;
  292.    if(M_ypos==11 && M_xpos >= 29 && M_xpos <= 51 && searched==1)
  293.    goto repeat;
  294.    if((key==27) || (M_ypos==8 && M_xpos>=22 && M_xpos<=24))
  295.    { srch.winremove();
  296.      _setcursortype(_NOCURSOR);
  297.      key=0;
  298.      return;
  299.     }
  300.    if((key=='\r') || (M_ypos==8 && M_xpos>=32 && M_xpos<=49))
  301.    { goto end;
  302.     }
  303.    if(key=='\b')
  304.    { bksp : if(count==0)
  305.      { goto rekey;
  306.       }
  307.      LAST_CHAR(searchstring) = NUL;
  308.      srch.winxy(srch.getx()-1,srch.gety());
  309.      srch << "░";
  310.      srch.winxy(srch.getx()-1,srch.gety());
  311.      count--;
  312.      goto rekey;
  313.     }
  314.    if((key < 32) || (key > 126))
  315.    { goto rekey;
  316.     }
  317.    sprintf(alpha,"%c",key);
  318.    srch << alpha;
  319.    if(count==0)
  320.    { strcpy(searchstring, alpha);
  321.     }
  322.    if(count>0)
  323.    { strcat(searchstring, alpha);
  324.     }
  325.    count++;
  326.    if(count==35)
  327.    { do {
  328.      key = getkey();
  329.      } while((key != '\r') && (key != '\b'));
  330.      if(key == '\b')
  331.      { goto bksp;
  332.       }
  333.      else
  334.      { goto end;
  335.       }
  336.     }
  337.    goto rekey;
  338.    end : if(count==0)
  339.      { goto rekey;
  340.       }
  341.  
  342.    // goto next location for search again, or BOF for new search //
  343.    repeat : if(key==317 || key==999) // jump here if repeat srch //
  344.    fseek(in, saveloc, SEEK_SET); // search forward from current loc //
  345.    else
  346.    { rewind(in); // reset to BOF //
  347.      lincount=0;
  348.     }
  349.  
  350.    // simple text search algorithm //
  351.    while(fgets(buffer, 255, in))
  352.    { lineloc=ftell(in);
  353.      found = strstr(strupr(buffer), strupr(searchstring));
  354.      if(found)
  355.      { searchloc = lineloc - (strlen(buffer)-1) + (found-buffer);
  356.        saveloc = searchloc+strlen(searchstring)-1; // save for next search //
  357.        for(a=0; a<=lastline; a++)
  358.        { if(loc[a] > searchloc) // get end loc of current line //
  359.      { a--;
  360.        break;
  361.       }
  362.     }
  363.        col = searchloc - loc[a] - 35; // always visible //
  364.        if(col<0)col=0;
  365.        searchsuccess=1;
  366.        break;
  367.       }
  368.      lincount++; // track lines for displaying found text //
  369.     }
  370.    _setcursortype(_NOCURSOR);
  371.  
  372.    // display found text or error msg if not //
  373.    if(searchsuccess==1)
  374.    { srch.winremove();
  375.      w1.wincls();
  376.      cnt=startcnt=lincount-8;
  377.      if(cnt<0)cnt=startcnt=0;
  378.      if(cnt>lastline-23)cnt=startcnt=lastline-23;
  379.      if(lastline<23)cnt=startcnt=0;
  380.      for(i=1; i<=23; i++)
  381.      { right=0;
  382.        read(); // regular read function //
  383.        if(ch == EOF)
  384.        { for(z=i;z<=23;z++)
  385.      rightarray[z]=0;
  386.      break;
  387.     }
  388.        if(right==1)
  389.        rightarray[i]=1;
  390.        else
  391.        rightarray[i]=0;
  392.       }
  393.      show_status();
  394.      key=0;
  395.      searched=1;
  396.      searchsuccess=0;
  397.      return;
  398.     }
  399.    else
  400.    { srch.wincls();
  401.      srch << "\n   Text not found.  Press any key... ";
  402.      srch.wcout(9,4,"─────────────────────────"); // erase search again //
  403.      getkey();
  404.      srch.winremove();
  405.      w1.wincls();
  406.      cnt=startcnt;
  407.      for(i=1; i<=23; i++)
  408.      { right=0;
  409.        read(); // regular read function //
  410.        if(ch == EOF)
  411.        { for(z=i;z<=23;z++)
  412.      rightarray[z]=0;
  413.      break;
  414.     }
  415.        if(right==1)
  416.        rightarray[i]=1;
  417.        else
  418.        rightarray[i]=0;
  419.       }
  420.      key=0;
  421.      saveloc=0;
  422.      lincount=0;
  423.      searched=0;
  424.      return;
  425.     }
  426.  }
  427. void home(void)
  428. {
  429.    if(cnt-23 <= 0)
  430.    return;
  431.    w1.wincls();
  432.    col = cnt = startcnt = 0;
  433.    for(i=1; i<=23; i++)
  434.    { right=0;
  435.      read(); // regular read function //
  436.      if(ch == EOF)
  437.      { for(z=i;z<=23;z++)
  438.        rightarray[z]=0;
  439.        break;
  440.       }
  441.      if(right==1)
  442.      rightarray[i]=1;
  443.      else
  444.      rightarray[i]=0;
  445.     }
  446.    show_status();
  447.  }
  448. void end(void)
  449. {  if (ch==EOF)
  450.    return;
  451.    w1.wincls();
  452.    col = 0;
  453.    cnt = startcnt = lastline-23;
  454.    for(i=1; i<=23; i++)
  455.    { right=0;
  456.      read(); // regular read function //
  457.      if(ch == EOF)
  458.      { for(z=i;z<=23;z++)
  459.        rightarray[z]=0;
  460.        break;
  461.       }
  462.      if(right==1)
  463.      rightarray[i]=1;
  464.      else
  465.      rightarray[i]=0;
  466.     }
  467.    show_status();
  468.  }
  469. void page_down(void)
  470. {
  471.    regs.h.ah = 0x0C; // fill union with clear keyboard buffer call //
  472.  
  473.    if (ch==EOF)
  474.    return;
  475.    w1.wincls();
  476.    if(cnt+23 > lastline)
  477.    cnt = lastline-23;
  478.    startcnt = cnt;
  479.    for(i=1; i<=23; i++)
  480.    { right=0;
  481.      read(); // regular read function //
  482.      if(ch == EOF)
  483.      { for(z=i;z<=23;z++)
  484.        rightarray[z]=0;
  485.        break;
  486.       }
  487.      if(right==1)
  488.      rightarray[i]=1;
  489.      else
  490.      rightarray[i]=0;
  491.     }
  492.    show_status();
  493.    int86(0x21, ®s, ®s); // clear keyb buffer to halt scrolling now //
  494.  }
  495. void page_up(void)
  496. {
  497.    regs.h.ah = 0x0C; // fill union with clear keyboard buffer call //
  498.  
  499.    if(cnt==23 || lastline <= 23)
  500.    return;
  501.    w1.wincls();
  502.    cnt = cnt-46;
  503.    if(cnt<0)cnt=0;
  504.    startcnt = cnt;
  505.    for(i=1; i<=23; i++)
  506.    { right=0;
  507.      read(); // regular read function //
  508.      if(ch == EOF)
  509.      { for(z=i;z<=3;z++)
  510.        rightarray[z]=0;
  511.        break;
  512.       }
  513.      if(right==1)
  514.      rightarray[i]=1;
  515.      else
  516.      rightarray[i]=0;
  517.     }
  518.    show_status();
  519.    int86(0x21, ®s, ®s); // clear keyb buffer to halt scrolling now //
  520.  }
  521. void arrow_down(void)
  522. {
  523.    regs.h.ah = 0x0C; // fill union with clear keyboard buffer call //
  524.  
  525.    if (ch==EOF)
  526.    return;
  527.    w1.winxy(0,0);
  528.    w1.wincleol();
  529.    scroll(0,1,7,1,1,23,78); // scroll screen up 1 line //
  530.    w1.winxy(0,22);
  531.    for(i=1;i<=23;i++)
  532.    { rightarray[i-1] = rightarray[i];
  533.     }
  534.    right=0;
  535.    startcnt = cnt;
  536.    read(); // regular read function //
  537.    if(right==1)
  538.    { rightarray[23]=1;
  539.     }
  540.    else
  541.    { rightarray[23]=0;
  542.     }
  543.    for(i=1;i<=23;i++)
  544.    { if(rightarray[i]==1)
  545.      right=1;
  546.     }
  547.    show_status();
  548.    int86(0x21, ®s, ®s); // clear keyb buffer to halt scrolling now //
  549.    return;
  550.  }
  551. void arrow_up(void)
  552. {
  553.    int savecnt; // control integer //
  554.    regs.h.ah = 0x0C; // fill union with clear keyboard buffer call //
  555.  
  556.    if(cnt - 23 <= 0)
  557.    return;
  558.    w1.winxy(0,22);
  559.    w1.wincleol();
  560.    scroll(1,1,7,1,1,23,78); // scroll screen dn 1 line //
  561.    w1.winxy(0,0);
  562.    savecnt=cnt-24;
  563.    cnt = startcnt = cnt-24;
  564.    for(i=23;i>=1;i--)
  565.    { rightarray[i+1] = rightarray[i];
  566.     }
  567.    right=0;
  568.    read(); // regular read function //
  569.    if(right==1)
  570.    { rightarray[1]=1;
  571.     }
  572.    else
  573.    { rightarray[1]=0;
  574.     }
  575.    for(i=1;i<=23;i++)
  576.    { if(rightarray[i]==1)
  577.      right=1;
  578.     }
  579.    cnt = savecnt+23;
  580.    show_status();
  581.    int86(0x21, ®s, ®s); // clear keyb buffer to halt scrolling now //
  582.    return;
  583.  }
  584. void arrow_left(void)
  585. {
  586.    regs.h.ah = 0x0C; // fill union with clear keyboard buffer call //
  587.  
  588.    if(col==0)
  589.    return;
  590.    if(cnt - 23 >= 0 && lastline > 22)
  591.    cnt = cnt - 23;
  592.    else
  593.    cnt = 0;
  594.    col -= 8;
  595.    if(col<0)col=0;
  596.    w1.wincls();
  597.    for(i=1; i<=23; i++)
  598.    { right=0;
  599.      read(); // regular read function //
  600.      if(ch == EOF)
  601.      { for(z=i;z<=23;z++)
  602.        rightarray[z]=0;
  603.        break;
  604.       }
  605.      if(right==1)
  606.      rightarray[i]=1;
  607.      else
  608.      rightarray[i]=0;
  609.     }
  610.    show_status();
  611.    int86(0x21, ®s, ®s); // clear keyb buffer to halt scrolling now //
  612.    return;
  613.  }
  614. void arrow_right(void)
  615. {
  616.    regs.h.ah = 0x0C; // fill union with clear keyboard buffer call //
  617.  
  618.    for(i=1;i<=23;i++)
  619.    { if(rightarray[i]==1)
  620.      right=1;
  621.     }
  622.    if(right==0)
  623.    return;
  624.    if(cnt - 23 >= 0 && lastline > 22)
  625.    cnt = cnt - 23;
  626.    else
  627.    cnt = 0;
  628.    col += 8;
  629.    w1.wincls();
  630.    for(i=1; i<=23; i++)
  631.    { right=0;
  632.      read(); // regular read function //
  633.      if(ch == EOF)
  634.      { for(z=i;z<=23;z++)
  635.        rightarray[z]=0;
  636.        break;
  637.       }
  638.      if(right==1)
  639.      rightarray[i]=1;
  640.      else
  641.      rightarray[i]=0;
  642.     }
  643.    show_status();
  644.    int86(0x21, ®s, ®s); // clear keyb buffer to halt scrolling now //
  645.    return;
  646.  }
  647. void new_file(void)
  648. {
  649.    // save current file name //
  650.    char *savefile = searchpath(filename);
  651.    w1.wincls();
  652.  
  653.    // close current file //
  654.    fclose(in);
  655.  
  656.    // get new filename //
  657.    file_select();
  658.    if(fail==1)
  659.    { if(nofile==0)
  660.      { in = fopen(savefile, "rb");
  661.        cnt=24; // trick home function //
  662.        startcnt=0;
  663.        home();
  664.        key=0;
  665.        return;
  666.       }
  667.      key=0;
  668.      return;
  669.     }
  670.  
  671.    // attemp to open file //
  672.    if((in = fopen(filename, "rb")) == NULL)
  673.    { w1 << "\n  Cannot open " << strupr(filename);
  674.      w1 << ".  Press any key to continue...";
  675.      getkey();
  676.      in = fopen(savefile, "rb");
  677.      cnt=24; // trick home function //
  678.      startcnt=0;
  679.      home();
  680.      return;
  681.     }
  682.  
  683.    // count lines and ensure line locations fit in memory //
  684.    num=0;
  685.    do
  686.    { ch = fgetc(in); // get char from file //
  687.      if(ch == '\n') // if it's a newline char... //
  688.      { num++; // increment location array //
  689.        if(num==1500)
  690.        pause_win("    Please wait while file is read and loaded...    ");
  691.        if(num>maxsize || ftell(in) > 600000) // 600k max size //
  692.        { pause.winremove();
  693.      w1 << "\n  " << filename << " is too large.  Press any key to continue...";
  694.      getkey();
  695.      fclose(in);
  696.      if(nofile==0)
  697.      { in = fopen(savefile, "rb");
  698.        cnt=24;
  699.        startcnt=0;
  700.        home(); // trick home function //
  701.        return;
  702.       }
  703.      pause.winremove();
  704.      w1.wincls();
  705.      return;
  706.     }
  707.       }
  708.     } while (ch != EOF);
  709.  
  710.    // display new filename //
  711.    show(3,25,"                    ");
  712.    sprintf(showstring, "File:  %s", strupr(filename)); // concat filename //
  713.    show(3,25,showstring); // show filename in lower bar //
  714.  
  715.    // pinpoint long locations for beginning of lines //
  716.    rewind(in); // reset to beginning of file //
  717.    loc[0] = ftell(in); // store BOF as loc[0] //
  718.    num=1;
  719.    do
  720.    { ch = fgetc(in); // get char from file //
  721.      if(ch == '\n') // if it's a newline char... //
  722.      { loc[num] = ftell(in); // store location in array //
  723.        num++; // increment location array //
  724.       }
  725.     } while (ch != EOF);
  726.    lastline=num; // save total as lastline //
  727.    pause.winremove();
  728.  
  729.    // display first screenfull with home function //
  730.    nofile=0;
  731.    cnt=24; // trick home function //
  732.    startcnt=0;
  733.    home();
  734.    return;
  735.  }
  736. void file_select(void)
  737. {
  738.    DIR *directory;
  739.    struct dirent *ent;
  740.    int save, disk, dirnum;
  741.    unsigned attrib;
  742.    char buffer[MAXPATH];
  743.    char string[15], temp[15];
  744.  
  745.    // start or newscan //
  746.    newscan : fail=0; dirnum=0; newscan=0;
  747.  
  748.    // get drives except current drive //
  749.    save = getdisk(); // save original disk for later reset //
  750.    for (disk = 0;disk < 26;++disk) // for a through z //
  751.    { setdisk(disk); // try to set disks //
  752.      if (disk == getdisk()) // if disk exists //
  753.      { if(save != disk) // and its not the current disk //
  754.        { sprintf(array[dirnum], "a[-%c-]", disk + 'A'); // copy into array //
  755.      dirnum++;            //  start with "a" to aid sorting later //
  756.     }
  757.       }
  758.     } setdisk(save); // reset to original disk //
  759.  
  760.    // open directory for reading //
  761.    if ((directory = opendir(getcwd(buffer, MAXPATH))) == NULL) // open //
  762.    { perror("Unable to open directory");
  763.      exit(1);
  764.     }
  765.  
  766.    // get directories and files //
  767.    while ((ent = readdir(directory)) != NULL) // read current directory //
  768.    { if(strcmp(ent->d_name,".") != 0) // skip root dir //
  769.      { _dos_getfileattr(ent->d_name,&attrib); // get attributes //
  770.        if(attrib & _A_SUBDIR || strcmp(ent->d_name,"..")==0) // if it is a subdirectory //
  771.        { sprintf(array[dirnum], "b%s\\", ent->d_name);
  772.      dirnum++;            //  start with "b" to aid sorting later //
  773.     }
  774.        else            // not system or hidden files //
  775.        { if(!(attrib & _A_HIDDEN || attrib & _A_SYSTEM))
  776.      { sprintf(array[dirnum], "c%s", ent->d_name);
  777.        dirnum++;            //  start with "c" to aid sorting later //
  778.       }
  779.     }
  780.       }
  781.      if(dirnum==100)
  782.      pause_win("  Please wait while directory listing is formed...  ");
  783.     }
  784.    closedir(directory); // close directory //
  785.  
  786.    // if sort by extension is requested, prepare entries by //
  787.    // changing from cfname.ext to cext.cfname //
  788.    if(sortorder==1) // if sort by extension is requested //
  789.    { for(i=0; i<dirnum; i++)
  790.      { if(array[i][0] == 'c')
  791.        { char *dot = strchr(array[i], '.');
  792.      if(dot) // if file has an extension //
  793.      { // prep for extension sort //
  794.        strcpy(string, array[i]);
  795.        char *ext = strchr(string, '.');
  796.        if(ext)
  797.        ext++;
  798.        strncpy(temp, string, ext-string-1);
  799.        temp[ext-string-1] = NUL;
  800.        sprintf(array[i], "c%s.%s", ext, temp);
  801.       }
  802.      else // if file has no extension put a space as the extension //
  803.      { strcpy(temp, array[i]);
  804.        sprintf(array[i], "c .%s", temp);
  805.       } // no extension files now guaranteed to be first after sort //
  806.     }
  807.       }
  808.     }
  809.  
  810.    // alhabetical sort by filename or extension as per request. //
  811.    // always a's (drives), then b's (directories), then c's (files) //
  812.    qsort((void *)array, dirnum, sizeof(array[0]), sort_function);
  813.  
  814.    // if sorted by extension, fix prepared entries by //
  815.    // changing back from cext.cfname to cfname.ext //
  816.    if(sortorder==1) // if sort by extension was requested //
  817.    { for(i=0; i<dirnum; i++)
  818.      { if(array[i][0] == 'c')
  819.        { char *dot = strchr(array[i], '.');
  820.      if(dot)
  821.      { if(array[i][1] != ' ') // if file had an extension //
  822.        { strrev(array[i]);
  823.          LAST_CHAR(array[i]) = NUL;
  824.          char *ext = strchr(array[i], '.');
  825.          if(ext)
  826.          ext++;
  827.          strncpy(temp, array[i], ext-array[i]-1);
  828.          temp[ext-array[i]-1] = NUL;
  829.          sprintf(array[i], "%s.%s", strrev(temp), strrev(ext));
  830.         }
  831.        else // if file had no extension remove the space //
  832.        { strrev(array[i]);
  833.          strncpy(temp, array[i], strlen(array[i])-3);
  834.          temp[strlen(array[i])-3] = NUL;
  835.          sprintf(array[i], "%s", strrev(temp));
  836.         }
  837.       }
  838.     }
  839.       }
  840.     }
  841.  
  842.    // remove sorting aid a's, b's, and c's //
  843.    for(i=0; i<=dirnum; i++)
  844.    { strrev(array[i]);
  845.      LAST_CHAR(array[i]) = NUL;
  846.      strrev(array[i]);
  847.     }
  848.    pause.winremove();
  849.  
  850.    // get file selection from scroll_select function //
  851.    scroll_select(dirnum); // dirnum is one more than numelements to keep //
  852.    if(newscan==1)         // the list null terminated for reliability //
  853.    { goto newscan;
  854.     }
  855.    return;
  856.  }
  857. int sort_function( const void *a, const void *b) // example from B TC 3.0 //
  858. {  // modified to sort a list of pointers to pointers of strings //
  859.    return strcmp(*(char **)a, *(char **)b);
  860. }
  861. void scroll_select(int numelements)
  862. {
  863.    int y, startnum, pagenum, elementnum, amount;
  864.    char drive[5];
  865.    int match[1000], m, matchnum; // for selecting by first letter //
  866.    int maxpage = ((numelements-1) / 17) + 1; // make 1st page = 1 //
  867.  
  868.    // build and display scroll window //
  869.    if(vmode == 3) { scrollwin.setcolor(white); scrollwin.setbkcolor(blue); }
  870.    else { scrollwin.setcolor(black); scrollwin.setbkcolor(lightgray); }
  871.    scrollwin.winput();
  872.    scrollwin.setcolor(lightgray); scrollwin.setbkcolor(black);
  873.    scrollwin.wincls();
  874.    show(33,3,"ESC=Abort");
  875.    show(47,3,"Up ");
  876.    show(47,23,"Dn ");
  877.    show(33,23,"F5=Chg-Sort");
  878.    Mtrap(32, 3, 50, 23);
  879.  
  880.    // display first screenfull //
  881.    if(numelements<17) amount = numelements-1;
  882.    else amount = 16;
  883.    scrollwin << "\n";
  884.    for(i=0;i<=amount;i++)
  885.    scrollwin << "  " << array[i] << "\n";
  886.    scrollwin.winxy(2,1); // position of first name //
  887.    scroll_show(array[0]); // show item 1 highlighted //
  888.    scrollwin.winxy(2,1); // position of first name //
  889.  
  890.    elementnum=0; startnum=0; pagenum=1; // reset all counters //
  891.    mcnt=0;
  892.    while(key != 27) // if not escape //
  893.    { switch(key = getkey()) {
  894.      case 27: fail=1; break;
  895.      case 9: /* tab */
  896.      case 327: /*home*/
  897.            if(elementnum==0)
  898.            break;
  899.            scrollwin.wincls();
  900.            if(numelements<17) amount = numelements-1;
  901.            else amount = 16;
  902.            scrollwin << "\n";
  903.            for(i=0;i<=amount;i++)
  904.            scrollwin << "  " << array[i] << "\n";
  905.            scrollwin.winxy(2,1); // position of first name //
  906.            scroll_show(array[0]); // show item 1 highlighted //
  907.            scrollwin.winxy(2,1); // position of first name //
  908.            elementnum=0; startnum=0; pagenum=1; // reset counters //
  909.            break;
  910.  
  911.      case 335: /*end*/
  912.            if(elementnum==numelements-1)
  913.            break;
  914.            pagenum=maxpage; // last page //
  915.            startnum = ((maxpage-1) * 17); // first element on last page //
  916.            elementnum=numelements-1; // last element number //
  917.            scrollwin.wincls();
  918.            scrollwin << "\n";
  919.            for(i=startnum;i<=numelements-1;i++)
  920.            scrollwin << "  " << array[i] << "\n";
  921.            i=elementnum-startnum; // position of element on page //
  922.            scrollwin.winxy(2,1+i); // move to position of element //
  923.            scroll_show(array[elementnum]); // highlighted //
  924.            scrollwin.winxy(2,1+i); // beginning of element //
  925.            break;
  926.  
  927.      case 319: /*F5*/
  928.            if(sortorder==0)
  929.            sortorder=1;
  930.            else
  931.            sortorder=0;
  932.            newscan=1;
  933.            scrollwin.winremove();
  934.            Mtrap(1,1,80,25);
  935.            return;
  936.  
  937.      case 336: /* dn */
  938.            if(elementnum==numelements-1)
  939.            break;
  940.            if(elementnum==startnum+16)
  941.            { goto pgdn;
  942.         }
  943.            scrollwin << array[elementnum]; // plain //
  944.            elementnum++;
  945.            y = scrollwin.gety() + 1;
  946.            scrollwin.winxy(2,y);
  947.            scroll_show(array[elementnum]); // highlighted //
  948.            scrollwin.winxy(2,y);
  949.            break;
  950.  
  951.      case 328: /* up */
  952.            if(elementnum==0)
  953.            break;
  954.            if(elementnum==startnum) // pgup w/last item highlighted //
  955.            { pagenum--;
  956.          startnum = (pagenum * 17) - 17;
  957.          scrollwin.wincls();
  958.          scrollwin << "\n";
  959.          for(i=startnum;i<=startnum+16;i++)
  960.          scrollwin << "  " << array[i] << "\n";
  961.          elementnum=startnum+16;
  962.          scrollwin.winxy(2,17); // position of last name //
  963.          scroll_show(array[elementnum]);
  964.          scrollwin.winxy(2,17); // position of last name //
  965.          break;
  966.         }
  967.            scrollwin << array[elementnum];
  968.            elementnum--;
  969.            y = scrollwin.gety() - 1;
  970.            scrollwin.winxy(2,y);
  971.            scroll_show(array[elementnum]);
  972.            scrollwin.winxy(2,y);
  973.            break;
  974.  
  975.      case 337: /*pgdn*/
  976.            pgdn : if(pagenum==maxpage)
  977.            break;
  978.            pagenum++;
  979.            elementnum = startnum = ((pagenum * 17) - 17);
  980.            scrollwin.wincls();
  981.            scrollwin << "\n";
  982.            if(startnum+17>numelements-1)
  983.            amount=numelements-1;
  984.            else
  985.            amount=startnum+16;
  986.            for(i=startnum;i<=amount;i++)
  987.            scrollwin << "  " << array[i] << "\n";
  988.            scrollwin.winxy(2,1); // position of first name //
  989.            scroll_show(array[elementnum]);
  990.            scrollwin.winxy(2,1); // position of first name //
  991.            break;
  992.  
  993.      case 329: /*pgup*/
  994.            if(pagenum==1)
  995.            break;
  996.            pagenum--;
  997.            elementnum = startnum = (pagenum * 17) - 17;
  998.            scrollwin.wincls();
  999.            scrollwin << "\n";
  1000.            for(i=startnum;i<=startnum+16;i++)
  1001.            scrollwin << "  " << array[i] << "\n";
  1002.            scrollwin.winxy(2,1); // position of first name //
  1003.            scroll_show(array[elementnum]);
  1004.            scrollwin.winxy(2,1); // position of first name //
  1005.            break;
  1006.  
  1007.      case 13:  /* enter */
  1008.            // drives - remove if not a directory list //
  1009.            if(array[elementnum][0] == '[' && array[elementnum][1] == '-'
  1010.            && array[elementnum][3] == '-' && array[elementnum][4] == ']')
  1011.            { sprintf(drive,"%c:", array[elementnum][2]);
  1012.          cd(drive);
  1013.          newscan=1;
  1014.          scrollwin.winremove();
  1015.          Mtrap(1,1,80,25);
  1016.          return;
  1017.         }
  1018.            // directories - remove if not a directory list //
  1019.            if(LAST_CHAR(array[elementnum]) == '\\')
  1020.            { LAST_CHAR(array[elementnum]) = NUL;
  1021.          chdir(array[elementnum]);
  1022.          newscan=1;
  1023.          scrollwin.winremove();
  1024.          Mtrap(1,1,80,25);
  1025.          return;
  1026.         }
  1027.            // any other type of item //
  1028.            // copy into any string or return the item //
  1029.            else
  1030.            { strcpy(filename,array[elementnum]); // copy to filename //
  1031.          scrollwin.winremove();
  1032.          Mtrap(1,1,80,25);
  1033.          return;
  1034.         }
  1035.  
  1036.      case 999: // mouse clicked //
  1037.            if(M_ypos==3 && M_xpos>=47 && M_xpos<=50)
  1038.            { /*pgup*/
  1039.          if(pagenum==1)
  1040.          break;
  1041.          pagenum--;
  1042.          elementnum = startnum = (pagenum * 17) - 17;
  1043.          scrollwin.wincls();
  1044.          scrollwin << "\n";
  1045.          for(i=startnum;i<=startnum+16;i++)
  1046.          scrollwin << "  " << array[i] << "\n";
  1047.          scrollwin.winxy(2,1); // position of first name //
  1048.          scroll_show(array[elementnum]);
  1049.          scrollwin.winxy(2,1); // position of first name //
  1050.          break;
  1051.         }
  1052.            if(M_ypos==23 && M_xpos>=47 && M_xpos<=50)
  1053.            { /*pgdn*/
  1054.          if(pagenum==maxpage)
  1055.          break;
  1056.          pagenum++;
  1057.          elementnum = startnum = ((pagenum * 17) - 17);
  1058.          scrollwin.wincls();
  1059.          scrollwin << "\n";
  1060.          if(startnum+17>numelements-1)
  1061.          amount=numelements-1;
  1062.          else
  1063.          amount=startnum+16;
  1064.          for(i=startnum;i<=amount;i++)
  1065.          scrollwin << "  " << array[i] << "\n";
  1066.          scrollwin.winxy(2,1); // position of first name //
  1067.          scroll_show(array[elementnum]);
  1068.          scrollwin.winxy(2,1); // position of first name //
  1069.          break;
  1070.         }
  1071.            if(M_xpos>34 && M_xpos<48 && M_ypos<22 && M_ypos>4)
  1072.            { // clicked on element //
  1073.          save=elementnum; // save current elementnum //
  1074.          elementnum = (M_ypos - 5) + startnum; // calculate new num //
  1075.          if(elementnum>numelements-1) // if past last item //
  1076.          { elementnum=save; // reset to original elementnum //
  1077.            break; // do nothing //
  1078.           }
  1079.          // drives - remove if not a directory list //
  1080.          if(array[elementnum][0] == '[' && array[elementnum][1] == '-'
  1081.          && array[elementnum][3] == '-' && array[elementnum][4] == ']')
  1082.          { sprintf(drive,"%c:", array[elementnum][2]);
  1083.            cd(drive);
  1084.            newscan=1;
  1085.            scrollwin.winremove();
  1086.            Mtrap(1,1,80,25);
  1087.            return;
  1088.           }
  1089.          // directories - remove if not a directory list //
  1090.          if(LAST_CHAR(array[elementnum]) == '\\')
  1091.          { LAST_CHAR(array[elementnum]) = NUL;
  1092.            chdir(array[elementnum]);
  1093.            newscan=1;
  1094.            scrollwin.winremove();
  1095.            Mtrap(1,1,80,25);
  1096.            return;
  1097.           }
  1098.          // any other item //
  1099.          // copy into any string or return the item //
  1100.          else
  1101.          { strcpy(filename,array[elementnum]); // cpy to flnm //
  1102.            scrollwin.winremove();
  1103.            Mtrap(1,1,80,25);
  1104.            return;
  1105.           }
  1106.         }
  1107.            // ESC //
  1108.            if(M_xpos>=33 && M_xpos<=35 && M_ypos==3)
  1109.            { key=27;
  1110.          fail=1;
  1111.          scrollwin.winremove();
  1112.          Mtrap(1,1,80,25);
  1113.          return;
  1114.         }
  1115.            if(M_xpos>=33 && M_xpos<=34 && M_ypos==23)
  1116.            { if(sortorder==0)
  1117.          sortorder=1;
  1118.          else
  1119.          sortorder=0;
  1120.          newscan=1;
  1121.          scrollwin.winremove();
  1122.          Mtrap(1,1,80,25);
  1123.          return;
  1124.         }
  1125.            break;
  1126.      default:  // speed select by first letter and move highlight //
  1127.            save=pagenum; // save current page number //
  1128.            matchnum=0; // zero match array //
  1129.            for(m=0; m<numelements; m++) // scan for matching first letters //
  1130.            { if(array[m][0] == toupper(key))
  1131.          { match[matchnum] = m;    // build array of all matches //
  1132.            matchnum++;
  1133.           }
  1134.         }
  1135.            if(matchnum==0) // no match found //
  1136.            { break;
  1137.         }
  1138.  
  1139.            // set number to first or next match //
  1140.            if(array[elementnum][0] == toupper(key)) // still in same letter selection //
  1141.            { m=elementnum+1; // advance by one //
  1142.          if(array[m][0] != toupper(key)) // if past last match //
  1143.          { for(i=m; i<numelements; i++) // test for split match //
  1144.            { if(array[i][0] == toupper(key))
  1145.              { m=i;
  1146.                break;
  1147.               }
  1148.              else  // if rest of array contains no more matches //
  1149.              m=match[0];
  1150.             }
  1151.           }
  1152.         }
  1153.            else // first time matching letter is pressed //
  1154.            { m=match[0];
  1155.         }
  1156.            if(m==numelements) // keep within list //
  1157.            m=match[0];
  1158.  
  1159.            // find page elementnum is on //
  1160.            pagenum=m / 17;
  1161.            if(pagenum == 0)
  1162.            pagenum=1;
  1163.            else
  1164.            pagenum=pagenum+1;
  1165.  
  1166.            // unhighlight current //
  1167.            scrollwin << array[elementnum];
  1168.  
  1169.            // calculate page of new element //
  1170.            startnum = ((pagenum * 17) - 17);
  1171.            elementnum=m; // new current element number //
  1172.  
  1173.            // show all elements on new page if not on current page //
  1174.            if(pagenum!=save)
  1175.            { scrollwin.wincls();
  1176.          scrollwin << "\n";
  1177.          if(startnum+17>numelements-1)
  1178.          amount=numelements-1;
  1179.          else
  1180.          amount=startnum+16;
  1181.          for(i=startnum;i<=amount;i++)
  1182.          scrollwin << "  " << array[i] << "\n";
  1183.         }
  1184.  
  1185.            // highlight correct element //
  1186.            i=elementnum-startnum; // position of element on page //
  1187.            scrollwin.winxy(2,1+i); // move to position of element //
  1188.            scroll_show(array[elementnum]); // highlighted //
  1189.            scrollwin.winxy(2,1+i); // reset to beginning of element //
  1190.  
  1191.            break; // end of default case //
  1192.       } // end of switch(key) //
  1193.     } // end if key==27 //
  1194.    key=0;
  1195.    scrollwin.winremove();
  1196.    Mtrap(1,1,80,25);
  1197.    return;
  1198.  }
  1199. int cd(char *cdname) // change to verified drive //
  1200. {
  1201.    int drivename, handle;
  1202.    char value[5], drvtest[15];
  1203.  
  1204.    drivename = cdname[0] - 'A';
  1205.    save = drivename; // save the drivename so it is still viable later //
  1206.    sprintf(drvtest, "%c:testtest.tst", cdname[0]); // build test name //
  1207.    sprintf(value, "0x%x",
  1208.    _dos_open(drvtest, O_RDONLY, &handle)); // test open on new drive //
  1209.    // new interrupt 24 handler will return to here with value if bad //
  1210.    if(strcmp(value, "0x3") == 0) // bad on floppy //
  1211.    { return -1; }
  1212.    if(strcmp(value, "0x5") == 0) // bad on CD or network //
  1213.    { return -1; }
  1214.    if((strcmp(value, "0x2") == 0)||(strcmp(value, "0x0") == 0)) // ok //
  1215.    setdisk(save); // set new drive //
  1216.    chdir("\\"); // set root directory //
  1217.    return 1;
  1218.  }
  1219. void read_help(void)
  1220. {
  1221.    if(vmode == 3) { help.setcolor(white); help.setbkcolor(blue); }
  1222.    else { help.setcolor(black); help.setbkcolor(lightgray); }
  1223.    help.winput();
  1224.    help.setcolor(lightgray); help.setbkcolor(black);
  1225.    help.wincls();
  1226.  
  1227.    qprintf(5,3,7,  "               General Instructions for READ File Viewer");
  1228.    qprintf(5,5,7,  "Overview:  READ is a simple text file viewer with many handy features");
  1229.    qprintf(5,6,7,  "such as full mouse support if a mouse is installed, Input File Selector,");
  1230.    qprintf(5,7,7,  "Text Search Utility, and a full compliment of status indicators such as");
  1231.    qprintf(5,8,7,  "Filename, Line total, Current line, Current column, and File percentage.");
  1232.    qprintf(5,9,7,  "Read also has a draggable scroll bar for file scrolling.");
  1233.    qprintf(5,11,7, "  Keyboard Usage:   Pg Up        =  move up one page in file");
  1234.    qprintf(5,12,7, "                    Pg Dn        =  move down one page in file");
  1235.    qprintf(5,13,7, "                    Left Arrow   =  move display left 8 spaces");
  1236.    qprintf(5,14,7, "                    Right Arrow  =  move display right 8 spaces");
  1237.    qprintf(5,15,7, "                    Home         =  move to start of file");
  1238.    qprintf(5,16,7, "                    End          =  move to end of file");
  1239.    qprintf(5,17,7, "                    F10          =  load new file");
  1240.    qprintf(5,18,7, "                    F2,F3        =  search, search again");
  1241.    qprintf(5,19,7, "                    ESC          =  exit viewer");
  1242.    qprintf(5,21,7, "  Mouse Usage:   The mouse is used by clicking on the name of the");
  1243.    qprintf(5,22,7, "                 desired function, such as: F1=Help, F2=Search,");
  1244.    qprintf(5,23,7, "                 F10=New, Home, End, PgUp, PgDn, <, >, or ESC.");
  1245.    while(key != 27)
  1246.    { switch(key = getkey()) {
  1247.      case 27: break;
  1248.      case 999: if(M_ypos == 1 && M_xpos >= 7 && M_xpos <= 9) { key = 27; } break;
  1249.      default: break;
  1250.      }
  1251.     }
  1252.    help.winremove();
  1253.    key=0;
  1254.    return;
  1255.  }
  1256. int error_win(char *msg)
  1257. {
  1258.    int xl, xr, half;
  1259.  
  1260.    half = strlen(msg) / 2;
  1261.    xl = 40 - half - 3;
  1262.    xr = 40 + half + 3;
  1263.    wintype err(xl, 10, xr, 12, 1, "");
  1264.    err.setcolor(white); if(vmode==3) err.setbkcolor(red);
  1265.    else err.setbkcolor(black); err.winput(); err.wincls();
  1266.    err.line_border();
  1267.    err << "  " << msg;
  1268.    Mtrap(1,1,80,25);
  1269.    rekey : switch(key = getkey())
  1270.    { case 27 :
  1271.      case 'A':
  1272.      case 'a': err.winremove(); return (_HARDERR_FAIL);
  1273.      case 'R':
  1274.      case 'r': err.winremove(); return (_HARDERR_RETRY);
  1275.      case 999 : if(M_ypos==12)
  1276.         { if((M_xpos>=(xl+strlen(msg)-17))&&(M_xpos<=(xl+strlen(msg)-11)))
  1277.           { return(_HARDERR_FAIL);
  1278.            }
  1279.           if((M_xpos>=(xl+strlen(msg)-7))&&(M_xpos<=(xl+strlen(msg)-1)))
  1280.           { return(_HARDERR_RETRY);
  1281.            }
  1282.          }
  1283.      default : goto rekey;
  1284.     }
  1285.  }
  1286. #pragma warn -par
  1287. void far handler(unsigned deverr, unsigned errval, unsigned far *devhdr)
  1288. {
  1289.    static char msg[80];
  1290.    int drive;
  1291.    int errorno;
  1292.  
  1293.    if (deverr & 0x8000) {
  1294.       error_win("Device error");
  1295.      _hardretn(5);
  1296.    }
  1297.    drive = deverr & 0x00FF;
  1298.    errorno = errval & 0x00FF;
  1299.    sprintf(msg, "%s on drive %c...   (A)bort   (R)etry   ?", err_msg[errorno], 'A' + drive);
  1300.    _hardresume(error_win(msg));
  1301. }
  1302. #pragma warn +par
  1303. int main(int argc, char *argv[])
  1304. {
  1305.    struct text_info ti; // structure to hold cursor position //
  1306.  
  1307.    // allocate far storage for 15000, or if not, 3000 line positions //
  1308.    loc=(unsigned long far *)farcalloc(15001,sizeof(unsigned long));
  1309.    if(loc != NULL) // should be able to get 15000 //
  1310.    maxsize=15000;
  1311.    else // can always get 3000 //
  1312.    { loc=(unsigned long far *)farcalloc(3001,sizeof(unsigned long));
  1313.      maxsize=3000;
  1314.     }
  1315.  
  1316.    // allocate storage for 1001 pointers to string pointers //
  1317.    array=(char **)calloc(1001,sizeof(char *));
  1318.  
  1319.    // allocate space for entry (except last to leave array null terminated) //
  1320.    for(i=0; i<1000; i++)
  1321.    array[i]=(char *)calloc(13,sizeof(char));
  1322.  
  1323.    // ensure mem is allocated //
  1324.    if(loc==NULL || array==NULL)
  1325.    { fprintf(stderr, "Error allocating memory.");
  1326.      exit(1);
  1327.     }
  1328.  
  1329.    // save original cursor position for restoration on exit //
  1330.    gettextinfo(&ti);
  1331.  
  1332.    // test for valid file on cmd line //
  1333.    if(argc>1)
  1334.    { if((in = fopen(argv[1], "rb")) == NULL)
  1335.      { printf("Cannot find file:  %s.  Press any key to select... ",strupr(argv[1]));
  1336.        getch();
  1337.        gotoxy(1,ti.cury);
  1338.        delline();
  1339.        gettextinfo(&ti);
  1340.        nofile=1;
  1341.       }
  1342.     }
  1343.  
  1344.    // screen and mouse initialization and setup //
  1345.    _harderr(handler); // install int 24 handler //
  1346.    set_v_ptr(); // set video pointer //
  1347.    qp_init(); // initialize qprintf fast screen writing //
  1348.    Mreset(); // reset mouse //
  1349.    Minsthandler(); // install mouse handler //
  1350.    mcnt=0; // set mouse repeat/delay monitor to zero //
  1351.    _setcursortype(_NOCURSOR); // turn off cursor //
  1352.    if(vmode==3) { w1.setcolor(white); w1.setbkcolor(blue); }
  1353.    else { w1.setcolor(black); w1.setbkcolor(lightgray); }
  1354.    fc = w1.getcolor(); // save forground color of border //
  1355.    bc = w1.getbkcolor(); // save background color of border //
  1356.    w1.winput(); // pop up window //
  1357.    w1.setcolor(lightgray); w1.setbkcolor(black); // set viewport to B/W //
  1358.    w1.wincls(); // clear viewport //
  1359.  
  1360.    // test command line arguments //
  1361.    if(argc < 2 || nofile==1)
  1362.    { nofile=1;
  1363.      strcpy(filename,"No File");
  1364.     }
  1365.  
  1366.    // attemp to open file if provided //
  1367.    if(nofile==0)
  1368.    { if((in = fopen(argv[1], "rb")) == NULL)
  1369.      { fprintf(stderr, "Error opening %s.", strupr(argv[1]));
  1370.        exit(1);
  1371.       }
  1372.     }
  1373.  
  1374.    // parse filename from argv[1] if provided //
  1375.    if(nofile==0)
  1376.    { char *pfile = strrchr(argv[1], '\\'); // search backwards for '\' //
  1377.      if(pfile) // if '\' //
  1378.      { pfile++; // increment into pfile //
  1379.        strcpy(filename, pfile); // copy pfile to filename for display //
  1380.       }
  1381.      else // if no '\' in argv[1] //
  1382.      { strcpy(filename, argv[1]); // copy argv[1] to filename for display //
  1383.       }
  1384.     }
  1385.  
  1386.    // write filename in lower bar //
  1387.    sprintf(showstring, "File:  %s", strupr(filename)); // concat filename //
  1388.    show(3,25,showstring); // show filename in lower bar //
  1389.  
  1390.    // pinpoint long locations for beginning of lines if file is provided //
  1391.    if(nofile==0)
  1392.    { num=0;
  1393.      do
  1394.      { ch = fgetc(in); // get char from file //
  1395.        if(ch == '\n') // if it's a newline char... //
  1396.        { num++; // increment location counter //
  1397.      if(num==1500)
  1398.      pause_win("    Please wait while file is read and loaded...    ");
  1399.      if(num>maxsize || ftell(in) > 600000) // max size 600k //
  1400.      { pause.winremove();
  1401.        w1.winremove();
  1402.        _setcursortype(_NORMALCURSOR);
  1403.        gotoxy(ti.curx,ti.cury);
  1404.        printf("File too large.");
  1405.        exit(1);
  1406.       }
  1407.     }
  1408.       } while (ch != EOF);
  1409.  
  1410.      // pinpoint long locations for beginning of lines //
  1411.      rewind(in); // reset to beginning of file //
  1412.      loc[0] = ftell(in); // store BOF as loc[0] //
  1413.      num=1;
  1414.      do
  1415.      { ch = fgetc(in); // get char from file //
  1416.        if(ch == '\n') // if it's a newline char... //
  1417.        { loc[num] = ftell(in); // store location in array //
  1418.      num++; // increment location array //
  1419.     }
  1420.       } while (ch != EOF);
  1421.      lastline=num; // save total as lastline //
  1422.      pause.winremove();
  1423.     }
  1424.  
  1425.    // make seek to desired line if argc 3 is provided //
  1426.    if(argc == 3)
  1427.    cnt = startcnt = ("%d") ? atoi(argv[2]) : 0;
  1428.    if(cnt < 0 || cnt > lastline) // if negative or larger than file //
  1429.    cnt = startcnt = 0;
  1430.  
  1431.    // display first screenfull if file is provided //
  1432.    if(nofile==0)
  1433.    { for(i=1; i<=23; i++)
  1434.      { right=0;
  1435.        read(); // regular read function //
  1436.        if(ch == EOF)
  1437.        { for(z=i;z<=23;z++)
  1438.      rightarray[z]=0;
  1439.      break;
  1440.     }
  1441.        if(right==1)
  1442.        rightarray[i]=1;
  1443.        else
  1444.        rightarray[i]=0;
  1445.       }
  1446.      show_status();
  1447.     }
  1448.  
  1449.    // if no file on cmd line, get one //
  1450.    if(nofile==1)
  1451.    new_file();
  1452.  
  1453.    searched=0; // no search conducted yet //
  1454.  
  1455.    // main user input and display processing loop //
  1456.    while(key != 27)
  1457.    { key=getkey();
  1458.      switch(key)
  1459.      { case 27: break;
  1460.        case 315: read_help(); break;
  1461.        case 324: searched=0; saveloc=0; lincount=0; new_file(); break;
  1462.        case 316: if(nofile==0) search(); break;
  1463.        case 327: if(nofile==0) home(); break;
  1464.        case 335: if(nofile==0) end(); break;
  1465.        case 329: if(nofile==0) page_up(); break;
  1466.        case 337: if(nofile==0) page_down(); break;
  1467.        case 328: if(nofile==0) arrow_up(); break;
  1468.        case 336: if(nofile==0) arrow_down(); break;
  1469.        case 331: if(nofile==0) arrow_left(); break;
  1470.        case 333: if(nofile==0) arrow_right(); break;
  1471.        case 999: // leftmouse //
  1472.          if(M_ypos == 1)
  1473.          { if(M_xpos >= 3 && M_xpos <= 5){ key = 27; break; }
  1474.            if(M_xpos >= 17 && M_xpos <= 23){ read_help(); break; }
  1475.            if(M_xpos >= 37 && M_xpos <= 43){ searched=0; saveloc=0; lincount=0; new_file(); break; }
  1476.            if(nofile==1) break;
  1477.            if(M_xpos >= 26 && M_xpos <= 34){ search(); break; }
  1478.            if(M_xpos >= 46 && M_xpos <= 49){ home(); break; }
  1479.            if(M_xpos >= 52 && M_xpos <= 54){ end(); break; }
  1480.            if(M_xpos >= 57 && M_xpos <= 60){ page_up(); break; }
  1481.            if(M_xpos >= 63 && M_xpos <= 66){ page_down(); break; }
  1482.            if(M_xpos == 69){ arrow_up(); break; }
  1483.            if(M_xpos == 72){ arrow_down(); break; }
  1484.            if(M_xpos == 75){ arrow_left(); break; }
  1485.            if(M_xpos == 78){ arrow_right(); break; }
  1486.           }
  1487.          if(M_xpos == 80)
  1488.          { if(nofile==1) break;
  1489.            if(M_ypos == 1){ arrow_up(); break; }
  1490.            if(M_ypos == 25){ arrow_down(); break; }
  1491.            if((M_ypos > ypos+1)&&(M_ypos < 25)){ page_down(); break; }
  1492.            if((M_ypos < ypos+1)&&(M_ypos > 1)){ page_up(); break; }
  1493.            if(M_ypos == ypos+1) // drag scroll bar //
  1494.            { do
  1495.              { if((M_ypos < ypos+1)&&(M_ypos >= 2)) // keep in range //
  1496.                { show(80,ypos+1,"░"); // redraw bar at old loc //
  1497.              show(80,M_ypos,""); // draw new pos indicator //
  1498.              ypos=ypos-1; // update yposition counter //
  1499.             }
  1500.                if((M_ypos > ypos+1)&&(M_ypos <= 24)) // keep in range //
  1501.                { show(80,ypos+1,"░"); // redraw bar at old loc //
  1502.              show(80,M_ypos,""); // draw new pos indicator //
  1503.              ypos=ypos+1; // update yposition counter //
  1504.             }
  1505.               } while(L_DOWN); // while dragging //
  1506.              if(ypos==1) // if top of scroll bar //
  1507.              home();
  1508.              else if(ypos==23) // if bottom of scroll bar //
  1509.              end();
  1510.              else
  1511.              jump_read(); // if somewhere else on scroll bar //
  1512.             }
  1513.            break;
  1514.           }
  1515.          break;
  1516.        default : break;
  1517.       }
  1518.     }
  1519.    // normal exit //
  1520.    if(in) // if file is open //
  1521.    fclose(in); // close input file //
  1522.    free(array); // free array memory //
  1523.    farfree(loc); // free far loc memory //
  1524.    w1.winremove(); // remove screen //
  1525.    _setcursortype(_NORMALCURSOR); // turn cursor back on //
  1526.    gotoxy(ti.curx, ti.cury); // goto saved cursor position //
  1527.    Mhide(); // hide mouse //
  1528.    Mreset(); // reset mouse //
  1529.    return 0; // exit //
  1530.  }
  1531.