home *** CD-ROM | disk | FTP | other *** search
/ GRIPS 2: Government Rast…rocessing Software & Data / GRIPS_2.cdr / dos / imdisp / source / imdisp.c < prev    next >
C/C++ Source or Header  |  1991-01-08  |  58KB  |  1,943 lines

  1. /*************************************************************/
  2. /*  Copyright (C) 1989, California Institute of Technology   */
  3. /*  U. S. Government Sponsorship under NASA Contract         */
  4. /*  NAS7-918 is acknowledged.                                */
  5. /*************************************************************/
  6.  
  7. /***  Program: IMDISP
  8.  
  9.      Interactive Image Display Program
  10.  
  11. ***/
  12.  
  13. /* * * * INCLUDE files * * * */
  14.  
  15. #include <conio.h>
  16. #include <ctype.h>
  17. #include <direct.h>
  18. #include <dos.h>
  19. #include <io.h>
  20. #include <malloc.h>
  21. #include <process.h>
  22. #include <signal.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include "imdef.h"
  27. #include "dispio.h"
  28. #include "disputil.h"
  29. #include "display.h"
  30. #include "fileio.h"
  31. #include "fileutil.h"
  32. #include "help.h"
  33. #include "imageio.h"
  34. #include "imagutil.h"
  35. #include "labutil.h"
  36. #include "plot.h"
  37. #include "refresh.h"
  38. #include "swap.h"
  39. #include "browse.h"
  40. #include "palette.h"
  41.  
  42. /* * * * External functions * * * */
  43.  
  44.  
  45. /* * * * Function declarations * * * */
  46.  
  47. int    BadStatus (char status[]);
  48. int    DoRefresh (void);
  49. int    SetValues (void);
  50. int    DoHistogram (void);
  51. int    DoPalette (void);
  52. int    DoPlot (void);
  53. int    DoStretch (void);
  54. int    DoCursor (void);
  55. int    DoProfile (void);
  56. int    StartUp (int argc, char **argv);
  57. int    DoSave (void);
  58. int    DoBatch (void);
  59. int    DoLabel (void);
  60. int    DoMenu (void);
  61. int    DoPosText (void);
  62. int    DoOverlay (void);
  63. int    DoSerial (void);
  64. int    DoPrint (void);
  65. int    ctrl_c (void);
  66. long   min3arr( long *, int);
  67. long   max3arr( long *, int);
  68. int    LoadPalette( char *);
  69.  
  70. /* * * * Global Variables * * * */
  71.  
  72. struct Color   CT[256];
  73. char   CommandString[80];
  74. int    nl, ns, bitsperpix;
  75. int    DNlow, DNhigh;
  76. int    OpenFileFlag;
  77. int    nld, nsd, sl, ss;
  78. int    nldd, nsdd, sldd, ssdd;
  79. int    subsample, zoom;
  80. int    centerline, centersamp;
  81. int    lastsl, lastss;
  82. FILE   *BatchFile;
  83.  
  84. long   Histogram;       /* Location of histogram in file */
  85. long   Palette;         /* Location of palette in file */
  86. char   PaletteFileName[64];
  87. int    Color_Hist;
  88. int    Microsoft;
  89. int    TurnCursorOff;    /* Set cursor funct. on */
  90. int    BatchFlag;        /* To control batch file on input cmd line */
  91. int    flowthru;
  92. int    IntoMem;
  93. int    abort_disp ;
  94.  
  95. int    ByteSwap = FALSE;
  96. char   memmsg[] = "Insufficient memory.";
  97. char   dirMask[30] = "*.*";              /* select all files */
  98. char   BrowseName[40] = "C:\\BROWSE.CMD"; /* default browse file name */
  99. char   MenuName[40] = "MENU.MNU";        /* default menu name */
  100.  
  101. FILE   *SelectFile;
  102. int    SelectFlag;       /* To control interactive selection of files */
  103. char   ImageFileName[80];
  104. char   SelectName[40] = "C:\\IMDISP.SEL"; /* default select file name */
  105.  
  106. /******************** Start of main program ***********************/
  107.  
  108. main (int argc, char *argv[])
  109.  
  110. {
  111. union    REGS  inregs, outregs;
  112. struct   SREGS segregs;
  113. unsigned int   cur_dseg_var;
  114. char           execute[80];
  115. int            command, len, i, j, k, flag;
  116. char           status[128], temp[136];
  117. char           DosCommand[72];
  118. char           *result, *comspec, *imbrowse, SwapName[40];
  119. int            swap_return, sys_return;
  120. unsigned char  exec_return;
  121.  
  122. signal(SIGINT,ctrl_c);
  123. /* ReduceDefaultData(); */
  124. StartUp (argc, argv);
  125. strcpy( SwapName, "C:\\IMDISWAP.FIL");
  126.  
  127.     do 
  128.     {
  129.        if (flowthru)
  130.        {
  131.            flowthru = 0;
  132.        }
  133.        else if (BatchFlag)
  134.        {
  135.            if (abort_disp == 1)
  136.                result = NULL;
  137.            else
  138.                result = fgets( CommandString, 127, BatchFile);
  139.            if (result == NULL)
  140.            {
  141.                fclose (BatchFile);
  142.                BatchFlag = 0;
  143.                if (SelectFlag)
  144.                {
  145.                   fclose (SelectFile);
  146.                   SelectFlag = 0;
  147.                }
  148.                strcpy (CommandString, "DONE");
  149.            }
  150.            if (strnicmp (CommandString, "SEL", 3) == 0)
  151.            {
  152.                SelectFile = fopen (SelectName, "w");
  153.                if (SelectFile == NULL)
  154.                {
  155.                   TextLine = 14;  TextSample = 1;
  156.                   WriteText ("Error in opening Select file");
  157.                }
  158.                else
  159.                   SelectFlag = 1;
  160.            }
  161.            if (strnicmp (CommandString, "PAU", 3) == 0)
  162.            {
  163.                GetKeywordInteger(CommandString, "PAU",0, &i, &flag);
  164.                if (flag < 1)
  165.                    GetKeywordInteger(CommandString, "pau",0, &i, &flag);
  166.          
  167.                if (flag==1) for (j=0; j<i*13; j++)
  168.                {
  169.                    for (k=0; k<32000; k++);
  170.                }
  171.                else
  172.                {
  173.                    StatusLine(0,"Pausing - Type any key to continue...");
  174.                    while(!kbhit); getch();
  175.                }
  176.            }
  177.            if (strnicmp(CommandString,"BAT",3) == 0 || abort_disp == 1)
  178.            {
  179.                fclose(BatchFile);
  180.                BatchFlag = 0;
  181.                if (SelectFlag)
  182.                {
  183.                   fclose(SelectFile);
  184.                   SelectFlag = 0;
  185.                }
  186.                abort_disp=0;
  187.            }
  188.            /* write the batch command line */
  189.            if (CommandString[strlen(CommandString)-1] == 0x0a)
  190.                CommandString[strlen(CommandString)-1] =  '\0';
  191.  
  192.            StatusLine(2,CommandString);
  193.            for (i=0;i<5000;i++); /* delay a bit */
  194.        }
  195.        else if (OneScreen)
  196.        {
  197.            abort_disp = 0;
  198.            StatusLine(2,"Command: ");
  199.            AcceptText (CommandString);
  200.            strcpy (temp, "Command: ");
  201.            strcat (temp, CommandString);
  202.            strcat (temp, " ");
  203.  
  204.            LengthText (temp, TextHeight, &len);
  205.            EraseText (TextLine, TextSample, TextHeight, len, 0);
  206.  
  207.        }
  208.        else
  209.        {
  210.            abort_disp = 0;
  211.            printf ("%s", "Command: ");
  212.            gets (CommandString);
  213.        }
  214.  
  215.        strupr (CommandString);
  216.        command = GetCommand (CommandString,
  217.        "FIL DIS ERA SET HIS PAL STR CUR PRO REF HEL EXI QUI DON BAT SAV CD  DIR TYP SYS >   MEN LAB TEX OVE BRO PLO SER PRI NEG");
  218. /* if you add more than 29 commands you must fix getcommand in PARAM.C */
  219.        switch (command)
  220.        {
  221.            case  1 : GetFile();            break;
  222.            case  2 : DisplayImage();       break;
  223.            case  3 : ClearDisplay(0);      break;
  224.            case  4 : SetValues();          break;
  225.            case  5 : DoHistogram();        break;
  226.            case  6 : DoPalette();          break;
  227.            case  7 : DoStretch();          break;
  228.            case  8 : DoCursor();           break;
  229.            case  9 : DoProfile();          break;
  230.            case 10 : DoRefresh();          break;
  231.            case 11 : GiveHelp();           break;
  232.            case 12 : /* exit command */    break;
  233.            case 13 : /* quit command */    break;
  234.            case 14 : /* done/null command*/break;
  235.            case 15 : DoBatch();            break;
  236.            case 16 : DoSave();             break;
  237.            case 17 :
  238.  
  239.                GetKeywordString (CommandString,"CD",".",temp, &flag);
  240.                result      = temp; /* change to char pointer */
  241.                segregs.ds  = FP_SEG(result);
  242.                inregs.h.ah = 0x3B;
  243.                inregs.x.dx = (unsigned)temp;
  244.                intdosx(&inregs,&outregs,&segregs);
  245.                break;
  246.  
  247.            case 18 :
  248.            case 19 :
  249.            case 20 :
  250.            case 21 :
  251.  
  252.                DisplayOff();
  253.                if (OpenFileFlag)
  254.                {
  255.                    CloseImage (0, status);
  256.                    if (BadStatus (status)) return;
  257.                    OpenFileFlag = 0;
  258.                }
  259.  
  260. /*               if (RefreshLines > 0) */
  261.                while (RefreshLines > 0)
  262.                    FreeRefresh( "sys cmd" );
  263.                comspec = getenv("COMSPEC");
  264.                if ((imbrowse = getenv("IMBROWSE")) != NULL)
  265.                {
  266.                    strcpy(SwapName, imbrowse);
  267.                    strcat(SwapName, "IMDISWAP.FIL");
  268.                }
  269.                if (command == 18 || command == 19)
  270.                {
  271.                    strcpy(execute, "/C ");
  272.                    strcat(execute,CommandString);
  273.                }
  274.                else 
  275.                {
  276.                    printf("Type \'exit\' to return to IMDISP.\n");
  277.                    strcpy(execute,"");
  278.                }
  279.                swap_return = swap(comspec, execute, &exec_return, SwapName);
  280.                if (swap_return == SWAP_NO_SAVE)
  281.                {
  282.                    printf( "Not much memory to work with...\n");
  283.                    sys_return = system( execute );
  284.                    if (sys_return != -1)
  285.                        swap_return = SWAP_OK;
  286.  
  287.                }
  288.                if (command == 18 || command == 19)
  289.                {
  290.                    printf("Type any key to continue:");
  291.                    while(!kbhit); getch();
  292.                }
  293.                DisplayOn();
  294.                WritePalette (DefaultPalette);
  295.                switch (swap_return)
  296.                {
  297.                    case SWAP_OK:
  298.                        StatusLine(0,"Successful, executed program returned.");
  299.                        break;
  300.  
  301.                    case SWAP_NO_SHRINK:
  302.                        StatusLine(0,"Unable to shrink DOS memory block.");
  303.                        break;
  304.  
  305.                    case SWAP_NO_SAVE:
  306.                        StatusLine(0,"Unable to save program to memory or disk.");
  307.                        break;
  308.  
  309.                    case SWAP_NO_EXEC:
  310.                        StatusLine(0,"DOS EXEC call failed.  Error is: ");
  311.                        switch (exec_return)
  312.                        {
  313.                            case BAD_FUNC:
  314.                                StatusLine (1,"Bad function.");
  315.                                break;
  316.                            case FILE_NOT_FOUND:
  317.                                StatusLine (1,"Program file not found.");
  318.                                break;
  319.                            case ACCESS_DENIED:
  320.                                StatusLine (1,"Access to program file denied.");
  321.                                break;
  322.                            case NO_MEMORY:
  323.                                StatusLine (1,"Insufficient memory to run program.");
  324.                                break;
  325.                            case BAD_ENVIRON:
  326.                                StatusLine (1,"Bad environment.");
  327.                                break;
  328.                            case BAD_FORMAT:
  329.                                StatusLine (1,"Bad format.");
  330.                                break;
  331.                            default:
  332.                                StatusLine (1,"Unexpected error code.");
  333.                                break;
  334.  
  335.                        }
  336.                }
  337.                break;
  338.  
  339.            case 22: DoMenu();              break;
  340.            case 23: DoLabel();             break;
  341.            case 24: DoPosText();           break;
  342.            case 25: DoOverlay();           break;
  343.            case 26: DoBrowse();            break;
  344.            case 27: DoPlot();              break;
  345.            case 28: DoSerial();            break;
  346.            case 29: DoPrint();             break;
  347.            case 30: DoNegative();          break;
  348.  
  349.            default : /* otherwise sound beep   */
  350.            {
  351.            /* check for drive change command */
  352.                if (strlen(CommandString) == 2 && CommandString[1] == ':')
  353.                    bdos(14,(int)CommandString[0]-'A',0);
  354.                else if ((strncmp(CommandString,"PAU",3) != 0) &&
  355.                         (strncmp(CommandString,"SEL",3) != 0))
  356.                {
  357.                    StatusLine(2,"INVALID! ");
  358.                    printf("\a");
  359.                    for (i=0;i<5000;i++);
  360.                }
  361.            }
  362.        }
  363.     } while ((command != 12) && (command != 13));
  364.  
  365.     if (OpenFileFlag)
  366.     {   
  367.        CloseImage (0, status);
  368.        BadStatus (status);
  369.     }
  370.     DisplayOff();
  371. }
  372.  
  373. int BadStatus (char * status)
  374. /* Prints out error message if there is one.
  375.    Returns true if error.
  376. */
  377.  
  378. {
  379.     if (strlen(status) > 0)
  380.     {
  381.         StatusLine(0,status);
  382.         return (1);
  383.     }
  384.     else
  385.         return (0);
  386. }
  387.  
  388. int DoRefresh(void)
  389. /*  DoRefresh performs the refresh command.
  390.     The whole display screen, or as much as there is in memory,
  391.     is redisplayed.
  392. */
  393. {
  394.     int  line;
  395.     unsigned char   *buffer;
  396.  
  397.     while ((buffer = malloc(dispns)) == NULL)
  398.       FreeRefresh("refr cmd");
  399.  
  400.     for (line = 1;  line <= RefreshLines;  line++)
  401.     {
  402.        GetRefresh (buffer, line, 1, dispns);
  403.        DisplayLine (buffer, line, 1, dispns);
  404.     }
  405.     free (buffer);
  406. }
  407.  
  408.  
  409. int SetValues(void)
  410. /*  SetValues performs the set command.
  411.     The DN range parameters are gotten and printed out.
  412. */
  413. {
  414.     int    newns;
  415.     int    swapflag, loflag, hiflag, refflag, dispflag, nsflag, broflag;
  416.     char   dispstr[128];
  417.  
  418.     GetKeywordInteger (CommandString, "LO", DNlow , &DNlow, &loflag);
  419.     if (loflag < 0)
  420.        GetKeywordInteger (CommandString, "DNL", DNlow , &DNlow, &loflag);
  421.     GetKeywordInteger (CommandString, "HI", DNhigh , &DNhigh, &hiflag);
  422.     if (hiflag < 0)
  423.        GetKeywordInteger (CommandString, "DNH", DNhigh , &DNhigh, &hiflag);
  424.     GetKeywordInteger (CommandString, "REF", RefreshLines, &RefreshLines, &refflag);
  425.     GetKeywordInteger (CommandString, "NS", IMCB[0].ns , &newns, &nsflag);
  426.     if (nsflag > 0)
  427.     {
  428.         IMCB[0].ns = newns;
  429.         IMCB[0].reclen = newns;
  430.     }
  431.  
  432.     GetKeywordString  (CommandString, "SWA", "","", &swapflag);
  433.     if (swapflag == 0) ByteSwap = FALSE;
  434.     GetKeywordString  (CommandString, "UNSWA", "","", &swapflag);
  435.     if (swapflag == 0) ByteSwap = TRUE;
  436.  
  437.     GetKeywordString  (CommandString, "BRO", "C:\\BROWSE.CMD" , BrowseName, &broflag);
  438.     GetKeywordString  (CommandString, "SEL", "C:\\BROWSE.SEL" , SelectName, &broflag);
  439.  
  440.     GetKeywordString  (CommandString, "DIS", "vga", dispstr, &dispflag);
  441.     if (dispflag > 0)
  442.     {
  443.        DisplayOff();
  444.        if (stricmp(dispstr, "cga"      ) == 0)
  445.            DisplayDevice = CGA;
  446.        else if (stricmp(dispstr, "ega480"   ) == 0)
  447.            DisplayDevice = EGA480;
  448.        else if (stricmp(dispstr, "ega"      ) == 0)
  449.            DisplayDevice = EGA350;
  450.        else if (stricmp(dispstr, "pga"      ) == 0)
  451.            DisplayDevice = PGA;
  452.        else if (stricmp(dispstr, "vga320"   ) == 0)
  453.            DisplayDevice = VGA200;
  454.        else if (stricmp(dispstr, "vga"      ) == 0)
  455.            DisplayDevice = VGA480;
  456.        else if (stricmp(dispstr, "orchid1024") == 0)
  457.            DisplayDevice = ORCHID768;
  458.        else if (stricmp(dispstr, "orchid800") == 0)
  459.            DisplayDevice = ORCHID600;
  460.        else if (stricmp(dispstr, "orchid"   ) == 0)
  461.            DisplayDevice = ORCHID480;
  462.        else if (stricmp(dispstr, "evga640"  ) == 0)
  463.            DisplayDevice = EVGA640;
  464.        else if (stricmp(dispstr, "evga512"  ) == 0)
  465.            DisplayDevice = EVGA512;
  466.        else if (stricmp(dispstr, "evga800"  ) == 0)
  467.            DisplayDevice = EVGA800;
  468.        else if (stricmp(dispstr, "bios"     ) == 0)
  469.            DisplayDevice = BIOS;
  470.        else if (stricmp(dispstr, "ati640"   ) == 0)
  471.            DisplayDevice = ATI640;
  472.        else if (stricmp(dispstr, "ati800"   ) == 0)
  473.            DisplayDevice = ATI800;
  474.        else if (stricmp(dispstr, "ati1024"  ) == 0)
  475.            DisplayDevice = ATI1024;
  476.        else if (stricmp(dispstr, "paradise" ) == 0)
  477.            DisplayDevice = PARADISE;
  478.  
  479.        DisplayOn();
  480.        WritePalette (DefaultPalette);
  481.     }
  482.  
  483.     if (DNlow > 32767)  DNlow = 32767;
  484.     if (DNhigh < DNlow+2)  DNhigh = DNlow + 2;
  485.  
  486.     if (loflag > 0 ||  hiflag > 0)
  487.     {
  488.        sprintf (dispstr, "DN low : %5d   DN high : %5d                 ", DNlow, DNhigh);
  489.        StatusLine(2,dispstr);
  490.     }
  491. }
  492.  
  493. int DoHistogram(void)
  494. /*  DoHistogram performs the histogram command.
  495.     First the parameter are scanned.  Then the image is read
  496.     in and the histogram calculated.  Finally DisplayHistogram
  497.     is called to plot it on the screen.  Different pieces of code
  498.     are used for different pixel formats.
  499. */
  500. {
  501.     int            hnld, hnsd, hsl, hss;
  502.     int            hnldd, hnsdd;
  503.     int            hsubsample;
  504.     int            line, samp, i, j;
  505.     int            DN, scale, flag, VoyFlag, VikFlag;
  506.     long int       histbuf[256];
  507.     char           status[128], dispstr[80], ch;
  508.     unsigned char  *buffer, *tempbuf;
  509.     int            *intbuf;
  510.  
  511.     if (OpenFileFlag == 0) 
  512.     {
  513.        StatusLine(0,"Use the \'FILE fname\' command to select image first");
  514.        return;
  515.     }
  516.  
  517.     if (bitsperpix == 32)
  518.     {
  519.     /* added by AEE: 01/17/90 */
  520.        StatusLine(0,"No histogram for 32 bits per pixel");
  521.        return;
  522.     }
  523.  
  524.     DrawBox (dispnl-45, 1, 46, dispns, 0);
  525.     for (DN = 0;  DN <= 255;  DN++)
  526.        histbuf[DN] = 0;
  527.  
  528.     GetKeywordSubcommand  (CommandString, "COL", &flag);
  529.     if (flag >= 0) Color_Hist= 1;
  530.       else Color_Hist = 0;
  531.  
  532.     GetKeywordSubcommand  (CommandString, "CEN", &flag);
  533.     if (flag == 0) 
  534.     {
  535.        hsl = lastsl;
  536.        hss = lastss;
  537.        hnld = nld;
  538.        hnsd = nsd;
  539.        if (hnld+hsl-1 > nl)
  540.            hnld = nl-hsl+1;
  541.        if (hnsd+hss-1 > ns)
  542.            hnsd = ns-hss+1;
  543.        hnldd = zoom*hnld / subsample;
  544.        hnsdd = zoom*hnsd / subsample;
  545.        if (hnldd+sldd-1 > dispnl)
  546.            hnldd = dispnl-sldd+1;
  547.        if (hnsdd+ssdd-1 > dispns)
  548.            hnsdd = dispns-ssdd+1;
  549.        hnld = subsample*hnldd / zoom;
  550.        hnsd = subsample*hnsdd / zoom;
  551.        hnldd = hnldd/zoom;
  552.        hnsdd = hnsdd/zoom;
  553.        hsubsample = subsample;
  554.     }
  555.     else 
  556.     {
  557.         GetKeywordInteger (CommandString, "NL", nl, &hnld, &flag);
  558.         GetKeywordInteger (CommandString, "NS", ns, &hnsd, &flag);
  559.         GetKeywordInteger (CommandString, "SL", 1, &hsl, &flag);
  560.         GetKeywordInteger (CommandString, "SS", 1, &hss, &flag);
  561.         GetKeywordInteger (CommandString, "SUB", 1, &hsubsample, &flag);
  562.         GetKeywordString  (CommandString, "VOY", " ",status,&VoyFlag);
  563.         GetKeywordString  (CommandString, "VIK", " ",status,&VikFlag);
  564.  
  565.         if (hnld+hsl-1 > nl)
  566.             hnld = nl-hsl+1;
  567.         if (hnsd+hss-1 > ns)
  568.             hnsd = ns-hss+1;
  569.         hnldd = hnld / hsubsample;
  570.         hnsdd = hnsd / hsubsample;
  571.     }
  572.  
  573.     if ((bitsperpix == 16) || (bitsperpix == 32))      /*  16 bit images */
  574.     {
  575.        while ((intbuf = (int *)malloc(2*hnsd)) == NULL)
  576.            FreeRefresh("intbuf 16");
  577.        scale = max( 1, ((DNhigh - DNlow) / 255) );
  578.        line = hsl;
  579.        for (i = 0;  i < hnldd;  i++)
  580.        {
  581.            ReadLine (0, intbuf, line, hss, hnsd, status);
  582.            if (BadStatus(status))
  583.                free(intbuf);
  584.            samp = 0;
  585.            for (j = 0;  j < hnsdd;  j++)
  586.            {
  587.                DN = intbuf[samp];
  588.                if (DN >= DNhigh)
  589.                    DN = DNhigh;
  590.                else if (DN <= DNlow)
  591.                    DN = DNlow;
  592.                DN = ((long)DN-DNlow) / scale;
  593.                DN = min( DN, 255);
  594.                DN = max( DN, 0);
  595.                (histbuf[DN])++;
  596.                samp += hsubsample;
  597.            }
  598.            line += hsubsample;
  599. /*
  600.    keyboard abort added
  601. */
  602.                if (kbhit())  /* abort disp if keypressed mdm 2/19/88*/
  603.                {
  604.                    if ((ch = getch()) == 0) ch = 0x80 | getch();
  605.                    if (ch != 17) /* don't abort if cntl q */
  606.                    {
  607.                        j=hnldd;
  608.                        abort_disp = 1;
  609.                    }
  610.                }
  611.        }
  612.        if (abort_disp != 1)
  613.            DisplayHistogram (histbuf, 256, DNlow, DNlow+256*scale);
  614.  
  615.        free(intbuf);
  616.     }
  617.  
  618.     else if (bitsperpix == 8)          /*  8 bit images */
  619.     {
  620.        while ((buffer = malloc(hnsd)) == NULL)
  621.            FreeRefresh("intbuf 8");
  622.  
  623.        if ((hss==1 && hnsd==800 && hsl==1 && hnld == 800 && hsubsample == 1
  624.              && VoyFlag == 0) ||
  625.            (hss==1 && hnsd==1204 && hsl==1 && hnld == 1056 && hsubsample == 1
  626.              && VikFlag == 0) || 
  627.            (hss==1 && hsl == 1 && hnld == nl && hnsd == ns && hsubsample == 1
  628.              && Histogram > 0L ))
  629.           /* read  histogram from file*/
  630.        {
  631.            /* location of vgr histo */
  632.            if (VoyFlag == 0)
  633.                Histogram = 671496L + (Microsoft*2048);
  634.  
  635.            /* location of vik histo */
  636.            if (VikFlag == 0)
  637.                Histogram = 1337472L + (Microsoft*2048);
  638.  
  639.            lseek(FCB[0].handle,Histogram,SEEK_SET);
  640.            read(FCB[0].handle,(char *)histbuf,1024);
  641.        }
  642.        else
  643.        {
  644.            line = hsl;
  645.            for (i = 0;  i < hnldd;  i++)
  646.            {
  647.                ReadLine (0, buffer, line, hss, hnsd, status);
  648.                if (BadStatus(status))
  649.                    free (buffer);
  650.                samp = 0;
  651.                for (j = 0;  j < hnsdd; j++)
  652.                {
  653.                    (histbuf[buffer[samp]])++;
  654.                    samp += hsubsample;
  655.                }
  656.                line += hsubsample;
  657. /*
  658.    keyboard abort added
  659. */
  660.                if (kbhit())  /* abort disp if keypressed mdm 2/19/88*/
  661.                {
  662.                    if ((ch = getch()) == 0) ch = 0x80 | getch();
  663.                    if (ch != 17) /* don't abort if cntl q */
  664.                    {
  665.                        j=hnldd;
  666.                        abort_disp = 1;
  667.                    }
  668.                }
  669.            }
  670.        }
  671.        if (abort_disp != 1)
  672.            DisplayHistogram (histbuf, 256, 0, 255);
  673.  
  674.        free (buffer);
  675.     }
  676.  
  677.     else                           /*  4 bit and 1 bit images */
  678.     {
  679.        while ((buffer = malloc(hnsd)) == NULL)
  680.            FreeRefresh("buf 4");
  681.        while ((tempbuf = malloc(hnsd)) == NULL)
  682.            FreeRefresh("temp buf");
  683.        line = hsl;
  684.        for (i = 0;  i < hnldd;  i++)
  685.        {
  686.            ReadLine (0, tempbuf, line, hss, hnsd, status);
  687.            if (BadStatus(status))
  688.            {
  689.                free (buffer);
  690.                free (tempbuf);
  691.            }
  692.            ConvertLine (tempbuf, buffer, bitsperpix, 8, hnsd, status);
  693.            samp = 0;
  694.            for (j = 0;  j < hnsdd; j++)
  695.            {
  696.                (histbuf[buffer[samp]])++;
  697.                samp += hsubsample;
  698.            }
  699.            line += hsubsample;
  700.         }
  701.         DisplayHistogram (histbuf, 16, 0, 15);
  702.  
  703.         free (buffer);  
  704.         free (tempbuf); 
  705.     }
  706.  
  707. }
  708.  
  709.  
  710. int DoPalette(void)
  711. /***   DoPalette performs the palette command.
  712.  
  713. ***/
  714. {
  715.     int    pseudo, flag, numdiddle, diddleflag;
  716.     int    i, color, saveflag, loadflag, showflag, eraseflag;
  717.     char   savename[64], loadname[64];
  718.     FILE   *unit;
  719.  
  720.     GetKeywordInteger (CommandString, "PS", 0, &pseudo, &flag);
  721.     GetKeywordInteger (CommandString, "EDI", numDN, &numdiddle, &diddleflag);
  722.     if (diddleflag < 0)
  723.        GetKeywordInteger (CommandString, "DID", numDN, &numdiddle, &diddleflag);
  724.     GetKeywordString (CommandString, "SAV", "IMDISP.PAL", savename, &saveflag);
  725.     GetKeywordString (CommandString, "LOA", "IMDISP.PAL", loadname, &loadflag);
  726.     GetKeywordSubcommand (CommandString, "DIS", &showflag);
  727.     GetKeywordSubcommand (CommandString, "ERA", &eraseflag);
  728.  
  729.     if (saveflag >= 0)
  730.     {
  731.        if ( (unit = fopen (savename, "w")) == NULL )
  732.            return;
  733.        ReadPalette (CT);
  734.        fprintf (unit, "CCSD3ZF0000100000001NJPL3IF0PDS200000001 = SFDU_LABEL\012");
  735.        fprintf (unit, "RECORD_TYPE                     = STREAM\012");
  736.        fprintf (unit, "FILE_RECORDS                    = %3d\012", 13+numDN);
  737.        fprintf (unit, "OBJECT                          = TABLE\012");
  738.        fprintf (unit, " TABLE_ROWS                      = %3d\012", numDN);
  739.        fprintf (unit, " ROW_COLUMNS                     = 4\012");
  740.        fprintf (unit, " COLUMN_NAME                     = (COLOR_NUMBER,\012");
  741.        fprintf (unit, "                                    RED_VALUE,\012");
  742.        fprintf (unit, "                                    GREEN_VALUE,\012");
  743.        fprintf (unit, "                                    BLUE_VALUE)\012");
  744.        fprintf (unit, " COLUMN_TYPE                     = (INTEGER,INTEGER,INTEGER,INTEGER)\012");
  745.        fprintf (unit, "END_OBJECT\012");
  746.        fprintf (unit, "END\012");
  747.  
  748.        for (i = 0;  i < numDN;  i++)
  749.            fprintf (unit, "%4d,%4d,%4d,%4d\012", i, CT[i].r, CT[i].g, CT[i].b);
  750.        fclose (unit);
  751.     }
  752.  
  753.     else if (loadflag >= 0)
  754.     {
  755.        LoadPalette(loadname);
  756.     }
  757.     else if (diddleflag >= 0)
  758.     {
  759.        DiddlePalette (numdiddle);
  760.     }
  761.     else if (showflag >= 0)
  762.     {
  763.        ShowPalette (numdiddle);
  764.     }
  765.     else if (eraseflag >= 0)
  766.     {
  767.        ErasePalette (numdiddle);
  768.     }
  769.  
  770.     else if (flag < 0) /* pal command with no args loads default */
  771.        WritePalette(DefaultPalette);
  772.     else
  773.     {
  774.        switch (pseudo)
  775.        {
  776.        case 0 :
  777.  
  778.                for (i = 0;  i < numDN;  i++)
  779.                {
  780.                    color = (16*i)/numDN;
  781.                    if (color > 15)  color = 15;
  782.                    CT[i].r = PScolor[color][0];
  783.                    CT[i].g = PScolor[color][1];
  784.                    CT[i].b = PScolor[color][2];
  785.                }
  786.                WritePalette (CT);
  787.                break;
  788.  
  789.        case 1 :
  790.  
  791.                if (DisplayDevice == ATI1024)
  792.                {
  793.                   for (i = 0; i < 256; i++)
  794.                   {
  795.                      CT[i].r = i;
  796.                      CT[i].g = i;
  797.                      CT[i].b = i;
  798.                   }
  799.                   WritePalette (CT);
  800.                }
  801.                else
  802.                   Stretch (0, numDN-1);
  803.                break;
  804.  
  805.        case 2 :
  806.  
  807.                for (i = 0;  i < numDN;  i++)
  808.                {
  809.                    color = (16*i)/numDN;
  810.                    if (color > 15)  color = 15;
  811.                    CT[i].r = Scolor[color][0];
  812.                    CT[i].g = Scolor[color][1];
  813.                    CT[i].b = Scolor[color][2];
  814.                }
  815.                WritePalette (CT);
  816.                break;
  817.  
  818.        case 3 :
  819.  
  820.                for (i = 0;  i < 256;  i++)
  821.                {
  822.                    CT[i].r = Redorange[i][0];
  823.                    CT[i].g = Redorange[i][1];
  824.                    CT[i].b = Redorange[i][2];
  825.                }
  826.  
  827.               if (numDN == 16)
  828.                 for (i=0;i<16;i++)
  829.                  {
  830.                   CT[i].r = CT[i*16+8].r;
  831.                   CT[i].g = CT[i*16+8].g;
  832.                   CT[i].b = CT[i*16+8].b;
  833.                  }
  834.  
  835.                WritePalette (CT);
  836.                break;
  837.  
  838.        case 4 :
  839.  
  840.                for (i = 0;  i < 256;  i++)
  841.                {
  842.                    CT[i].r = Prism[i][0];
  843.                    CT[i].g = Prism[i][1];
  844.                    CT[i].b = Prism[i][2];
  845.                }
  846.  
  847.               if (numDN == 16)
  848.                {
  849.                 for (i=0;i<16;i++)
  850.                  {
  851.                   CT[i].r = CT[i*16+8].r;
  852.                   CT[i].g = CT[i*16+8].g;
  853.                   CT[i].b = CT[i*16+8].b;
  854.                  }
  855.                /* special fix to display text */
  856.                CT[15].r=255; CT[15].g=255; CT[15].b=255;
  857.                }
  858.                WritePalette (CT);
  859.                break;
  860.  
  861.        case 5 :
  862.  
  863.                for (i = 0;  i < 256;  i++)
  864.                {
  865.                    CT[i].r = Topo[i][0];
  866.                    CT[i].g = Topo[i][1];
  867.                    CT[i].b = Topo[i][2];
  868.                }
  869.  
  870.               if (numDN == 16)
  871.                 for (i=0;i<16;i++)
  872.                  {
  873.                   CT[i].r = CT[i*16+8].r;
  874.                   CT[i].g = CT[i*16+8].g;
  875.                   CT[i].b = CT[i*16+8].b;
  876.                  }
  877.  
  878.                WritePalette (CT);
  879.                break;
  880.  
  881.        case 6 :
  882.  
  883.                for (i = 0;  i < 256;  i++)
  884.                {
  885.                    CT[i].r = Contour[i][0];
  886.                    CT[i].g = Contour[i][1];
  887.                    CT[i].b = Contour[i][2];
  888.                }
  889.  
  890.               if (numDN == 16)
  891.                 for (i=0;i<16;i++)
  892.                  {
  893.                   CT[i].r = CT[i*16+8].r;
  894.                   CT[i].g = CT[i*16+8].g;
  895.                   CT[i].b = CT[i*16+8].b;
  896.                  }
  897.  
  898.                WritePalette (CT);
  899.                break;
  900.  
  901.        case 7 :
  902.  
  903.                for (i = 0;  i < 256;  i++)
  904.                {
  905.                    CT[i].r = BGRY[i][0];
  906.                    CT[i].g = BGRY[i][1];
  907.                    CT[i].b = BGRY[i][2];
  908.                }
  909.  
  910.               if (numDN == 16)
  911.                {
  912.                 for (i=0;i<16;i++)
  913.                  {
  914.                   CT[i].r = CT[i*16+8].r;
  915.                   CT[i].g = CT[i*16+8].g;
  916.                   CT[i].b = CT[i*16+8].b;
  917.                  }
  918.                /* special fix to display text */
  919.                CT[15].r=255; CT[15].g=255; CT[15].b=255;
  920.                }
  921.  
  922.                WritePalette (CT);
  923.                break;
  924.        case 8 :
  925.  
  926.                for (i = 0;  i < 256;  i++)
  927.                {
  928.                    CT[i].r = Glasses1[i][0];
  929.                    CT[i].g = Glasses1[i][1];
  930.                    CT[i].b = Glasses1[i][2];
  931.                }
  932.  
  933.               if (numDN == 16)
  934.                 for (i=0;i<16;i++)
  935.                  {
  936.                   CT[i].r = CT[i*16+8].r;
  937.                   CT[i].g = CT[i*16+8].g;
  938.                   CT[i].b = CT[i*16+8].b;
  939.                  }
  940.  
  941.                WritePalette (CT);
  942.                break;
  943.        case 9 :
  944.  
  945.                for (i = 0;  i < 256;  i++)
  946.                {
  947.                    CT[i].r = Glasses2[i][0];
  948.                    CT[i].g = Glasses2[i][1];
  949.                    CT[i].b = Glasses2[i][2];
  950.                }
  951.  
  952.               if (numDN == 16)
  953.                 for (i=0;i<16;i++)
  954.                  {
  955.                   CT[i].r = CT[i*16+8].r;
  956.                   CT[i].g = CT[i*16+8].g;
  957.                   CT[i].b = CT[i*16+8].b;
  958.                  }
  959.  
  960.                WritePalette (CT);
  961.                break;
  962.  
  963.        }
  964.     }
  965. }
  966.  
  967. int LoadPalette(char * palettefile)
  968. /* LoadPalette reads in the color palette from the given palette filename
  969.    (palettefile).  This code originally resided in the DoPalette routine,
  970.    but was moved into its own routine to accomodate detached palette
  971.    processing -- Ron Baalke -- 07/27/90 */
  972. {
  973.     int    i, n, r, g, b, result;
  974.     unsigned char color[256];
  975.     char   filedata[133];
  976.     FILE   *unit;
  977.  
  978.     if (Palette != 0L)
  979.     {
  980.        lseek(FCB[0].handle, Palette, SEEK_SET);
  981.        read(FCB[0].handle, color, 256);
  982.        for (i=0;i<256;i++)
  983.           CT[i].r = color[i];
  984.        read(FCB[0].handle, color, 256);
  985.        for (i=0;i<256;i++)
  986.           CT[i].g = color[i];
  987.        read(FCB[0].handle, color, 256);
  988.        for (i=0;i<256;i++)
  989.           CT[i].b = color[i];
  990.        WritePalette (CT);
  991.        Palette = 0L; /* reset value to zero */
  992.        return(0);
  993.     }
  994.     if ((unit = fopen (palettefile, "r")) == NULL)
  995.     {
  996.            StatusLine(0,"Palette file not found.");
  997.            return;
  998.     }
  999.  
  1000.     fgets(filedata,132,unit);
  1001. /*
  1002.     if (strnicmp(filedata,"CCSD",4) == 0 || strnicmp(filedata,"NJPL",4) == 0)
  1003.     {
  1004. */
  1005.        do
  1006.        {
  1007.            fgets(filedata,132,unit);
  1008.            if (strnicmp(filedata,"END",3) == 0 &&
  1009.               (strlen(filedata) <= 5 || filedata[3] == ' '))
  1010.                    break;
  1011.        } while (!feof(unit));
  1012.        fgets (filedata, 132, unit);
  1013. /*
  1014.     }
  1015. */
  1016.     /* zero out palette but make highest value white */
  1017.     for (i=0;i<255;i++)
  1018.            CT[i].r = CT[i].g = CT[i].b = 0;
  1019.     if (numDN == 256)
  1020.            CT[255].r = CT[255].g = CT[255].b = 255;
  1021.     else
  1022.            CT[15].r  = CT[15].g  = CT[15].b  = 255;
  1023.  
  1024.     i = 0;
  1025.     do
  1026.     {
  1027.         result = sscanf(filedata, "%d %d %d %d", &n,&r,&g,&b);
  1028.         if (result == 1) /* try comma separated value */
  1029.             result = sscanf(filedata, "%d,%d,%d,%d", &n,&r,&g,&b);
  1030.         if (result == 3) /* no index value on line */
  1031.             {CT[i].r = n; CT[i].g = r; CT[i].b = g;}
  1032.         else if (result == 4 && (n >= 0 && n <= 256))
  1033.             {
  1034.              if (i==n-1) n = i; /* patch to handle old palettes */
  1035.                                 /* with values from 1 to 256    */
  1036.              CT[n].r = r; CT[n].g = g; CT[n].b = b;}
  1037.         else
  1038.         {
  1039.             StatusLine (0,"Invalid Palette file format.");
  1040.             fclose(unit); return;
  1041.         }
  1042.         i++;
  1043.         fgets (filedata, 132, unit);
  1044.     } while (! feof(unit) && i < 256);
  1045.  
  1046.     if (numDN == 16 && i > 15)
  1047.         for (i=0;i<16;i++)
  1048.         {
  1049.             CT[i].r = CT[i*16+8].r;
  1050.             CT[i].g = CT[i*16+8].g;
  1051.             CT[i].b = CT[i*16+8].b;
  1052.         }
  1053.     WritePalette (CT);
  1054.     fclose (unit);
  1055. }
  1056.  
  1057.  
  1058. int DoPlot()
  1059. /*
  1060.     DoPlot performs the plot command.  First the parameters are scanned.
  1061.     Then the image is read in and plotted.  Ordered pairs are plotted by
  1062.     Plotpair, other data by Plot32.
  1063. */
  1064. {
  1065.     int            wordbits=16, longbits=32;
  1066.     int            line, i, k, zoom, color, symbolflag;
  1067.     int            lineflag, ovlflag, zoomflag, minflag, maxflag;
  1068.     char           status[128], Symbol[2], PlotOvly;
  1069.     long           miny=0x7FFFFFFF, maxy=0x80000000;
  1070.     long           minx=0x7FFFFFFF, maxx=0x80000000;
  1071.  
  1072.     long           *buf32, *xbuf, *ybuf;
  1073.     unsigned char  *buffer;
  1074.     int            *intbuf;
  1075.  
  1076.     GetKeywordSubcommand (CommandString, "OVE", &ovlflag);
  1077.     if (ovlflag == 1)
  1078.     {
  1079.     /* OVErlay specified, don't clear the screen */
  1080.         PlotOvly = 'Y';
  1081.     }
  1082.     else
  1083.     {
  1084.         ClearDisplay(0);
  1085.         PlotOvly = 'N';
  1086.     }
  1087.  
  1088.  
  1089.     GetKeywordSubcommand (CommandString, "ZOO", &zoomflag);
  1090.     if (zoomflag == 1)
  1091.         zoom = 1;
  1092.     else
  1093.     /* ZOOm not specified, don't ask to zoom plot */
  1094.         zoom = 0;
  1095.  
  1096.     GetKeywordInteger (CommandString, "LIN", 1, &line, &lineflag);
  1097.     if (line > nl || line < 1)
  1098.         line = 1;
  1099.  
  1100.     GetKeywordInteger (CommandString, "COL", numDN-1, &color, &lineflag);
  1101.     GetKeywordLong (CommandString, "MIN", miny, &miny, &minflag);
  1102.     GetKeywordLong (CommandString, "MAX", maxy, &maxy, &maxflag);
  1103.     GetKeywordString (CommandString, "SYM", "", Symbol, &symbolflag);
  1104.  
  1105.     if (PDSused == 1 && switched == 1 && ns == 1 && nl > 1)
  1106.     {
  1107.     /*PDS label used */
  1108.        i    = nl;
  1109.        nl   = ns;
  1110.        ns   = i;
  1111.     }
  1112.  
  1113.     /* Allocate enough memory for the 32-bit buffers */
  1114.     while ((buf32 = (long *)malloc(4*ns)) == NULL)
  1115.     {
  1116.         RefreshLines -= 1;
  1117.         free (RefreshBuf[RefreshLines]);
  1118.         if (RefreshLines == 0)
  1119.         {
  1120.             DisplayOff();
  1121.             printf("Not enough memory to run program");
  1122.             exit(1);
  1123.         }
  1124.     }
  1125.  
  1126.  
  1127.     if ( (ns == 2 || ns == 3) && bitsperpix == 32)
  1128.     {
  1129.  
  1130.         while ((xbuf = (long *)malloc(4*nl)) == NULL)
  1131.         {
  1132.             RefreshLines -= 1;
  1133.             free (RefreshBuf[RefreshLines]);
  1134.             if (RefreshLines == 0)
  1135.             {
  1136.                 DisplayOff();
  1137.                 printf("Not enough memory to run program");
  1138.                 free(buf32);
  1139.                 exit(1);
  1140.             }
  1141.         }
  1142.  
  1143.         while ((ybuf = (long *)malloc(4*nl)) == NULL)
  1144.         {
  1145.             RefreshLines -= 1;
  1146.             free (RefreshBuf[RefreshLines]);
  1147.             if (RefreshLines == 0)
  1148.             {
  1149.                 DisplayOff();
  1150.                 printf("Not enough memory to run program");
  1151.                 free(xbuf);
  1152.                 free(buf32);
  1153.                 exit(1);
  1154.             }
  1155.         }
  1156.    /* 32 bit samples, ordered pairs */
  1157.        k = 0;
  1158.        for (i = 0;  i < nl;  i++)
  1159.        {
  1160.            ReadLine (0, buf32, line, 1, ns, status);
  1161.            if (BadStatus(status))
  1162.            {
  1163.                free(ybuf);
  1164.                free(xbuf);
  1165.                free(buf32);
  1166.                return;
  1167.            }
  1168.            xbuf[i] = buf32[0];
  1169.            ybuf[i] = buf32[1];
  1170.            line++;
  1171.            k++;
  1172.        }
  1173.  
  1174.        for (i=0; i<nl; i++)
  1175.        {
  1176.            if (xbuf[i] < minx)
  1177.                minx = xbuf[i];
  1178.            if (xbuf[i] > maxx)
  1179.                maxx = xbuf[i];
  1180.        }
  1181.        if (minflag < 1)
  1182.        {
  1183.            miny = min3arr( ybuf, nl);
  1184.            miny = miny + miny/10;
  1185.        }
  1186.        if (maxflag < 1)
  1187.        {
  1188.            maxy = max3arr( ybuf, nl);
  1189.            maxy = maxy + maxy/10;
  1190.        }
  1191.  
  1192.        Plotpair( xbuf, ybuf, minx, maxx, miny, maxy, k, Symbol, color, zoom);
  1193.        TextLine = TextHeight + 5; TextSample = 1;
  1194.        free(ybuf);
  1195.        free(xbuf);
  1196.        free(buf32);
  1197.        return;
  1198.     }
  1199.  
  1200.     if (ns != 2)  /*  images (not pairs) */
  1201.     {
  1202.        if (bitsperpix == 8)          /*  8 bit images */
  1203.        {
  1204.           while ((buffer = malloc(ns)) == NULL)
  1205.           {
  1206.               RefreshLines -= 1;
  1207.               free (RefreshBuf[RefreshLines]);
  1208.               if (RefreshLines == 0)
  1209.               {
  1210.                   DisplayOff();
  1211.                   printf("Not enough memory to run program");
  1212.                   exit(1);
  1213.               }
  1214.           }
  1215.  
  1216.           ReadLine( 0, buffer, line, 1, ns, status);
  1217.           if (BadStatus(status))
  1218.           {
  1219.               free (buffer);
  1220.               free (buf32);
  1221.               return;
  1222.           }
  1223.  
  1224.           ConvertLine( buffer, buf32, bitsperpix, longbits, ns, status);
  1225.           free (buffer);
  1226.        }
  1227.  
  1228.        else if (bitsperpix == 16)          /* 16 bit images */
  1229.        {
  1230.           while ((intbuf = malloc(2*ns)) == NULL)
  1231.           {
  1232.               RefreshLines -= 1;
  1233.               free (RefreshBuf[RefreshLines]);
  1234.               if (RefreshLines == 0)
  1235.               {
  1236.                   DisplayOff();
  1237.                   printf("Not enough memory to run program");
  1238.                   exit(1);
  1239.               }
  1240.           }
  1241.  
  1242.           ReadLine( 0, intbuf, line, 1, ns, status);
  1243.           if (BadStatus(status))
  1244.           {
  1245.               free (intbuf);
  1246.               free (buf32);
  1247.               return;
  1248.           }
  1249.  
  1250.           ConvertLine( intbuf, buf32, bitsperpix, longbits, ns, status);
  1251.           free (intbuf);
  1252.        }
  1253.        else if (bitsperpix == 32)          /* 32 bit images */
  1254.        {
  1255.            ReadLine (0, buf32, line, 1, ns, status);
  1256.            if (BadStatus(status))
  1257.            {
  1258.                free(buf32);
  1259.                return;
  1260.            }
  1261.        }
  1262.  
  1263.        if (minflag < 1)
  1264.        {
  1265.            miny = min3arr( buf32, ns);
  1266.            miny = miny + miny/10;
  1267.        }
  1268.  
  1269.        if (maxflag < 1)
  1270.        {
  1271.            maxy = max3arr( buf32, ns);
  1272.            maxy = maxy + maxy/10;
  1273.        }
  1274.  
  1275.        Plot32( buf32, miny, maxy, ns, Symbol, color, zoom);
  1276.        TextLine = TextHeight + 5; TextSample = 1;
  1277.        free(buf32);
  1278.        return;
  1279.     }
  1280. }
  1281.  
  1282. long   min3arr( long * buf, int nvals)
  1283. /*
  1284.     Finds the third smallest value in a 32-bit integer array
  1285. */
  1286. {
  1287.     long   min1 = 0x7fffffff, min2 = 0x7fffffff, min3 = 0x7fffffff;
  1288.     int    i;
  1289.  
  1290.     for ( i=0; i<nvals; i++)
  1291.     {
  1292.        if (buf[i] < min1)
  1293.        {
  1294.            min3 = min2;
  1295.            min2 = min1;
  1296.            min1 = buf[i];
  1297.        }
  1298.        else if (buf[i] < min2)
  1299.        {
  1300.            min3 = min2;
  1301.            min2 = buf[i];
  1302.        }
  1303.        else if (buf[i] < min3)
  1304.        {
  1305.            min3 = buf[i];
  1306.        }
  1307.     }
  1308.     if (nvals > 2)
  1309.        return(min3);
  1310.     else
  1311.        return(min1);
  1312. }
  1313.  
  1314.  
  1315. long   max3arr( long * buf, int nvals)
  1316. /*
  1317.     Finds the third largest value in a 32-bit integer array
  1318. */
  1319. {
  1320.     long   max1 = 0x80000000, max2 = 0x80000000, max3 = 0x80000000;
  1321.     int    i;
  1322.  
  1323.     for ( i=0; i<nvals; i++)
  1324.     {
  1325.        if (buf[i] > max1)
  1326.        {
  1327.            max3 = max2;
  1328.            max2 = max1;
  1329.            max1 = buf[i];
  1330.        }
  1331.        else if (buf[i] > max2)
  1332.        {
  1333.            max3 = max2;
  1334.            max2 = buf[i];
  1335.        }
  1336.        else if (buf[i] > max3)
  1337.        {
  1338.            max3 = buf[i];
  1339.        }
  1340.     }
  1341.     if (nvals > 2)
  1342.        return(max3);
  1343.     else
  1344.        return(max1);
  1345. }
  1346.  
  1347. int DoStretch(void)
  1348. /*  DoStretch performs the stretch command.
  1349. */
  1350. {
  1351.     int DNlow, DNhigh, flag;
  1352.  
  1353.     GetKeywordInteger (CommandString, "LO", 0, &DNlow, &flag);
  1354.     if (flag < 0)
  1355.        GetKeywordInteger (CommandString, "DNL", 0 , &DNlow, &flag);
  1356.     GetKeywordInteger (CommandString, "HI", numDN-1, &DNhigh, &flag);
  1357.     if (flag < 0)
  1358.        GetKeywordInteger (CommandString, "DNH", numDN-1 , &DNhigh, &flag);
  1359.     Stretch (DNlow, DNhigh);
  1360. }
  1361.  
  1362. int DoCursor(void)
  1363. /*  DoCursor performs the cursor command.
  1364.     After cursor mode the image line and sample are calculated and displayed.
  1365. */
  1366. {
  1367.     int    line, samp, i, len;
  1368.     char   dispstr[64];
  1369.  
  1370.     StatusLine(1,"Arrow keys move; +,- changes cursor increment; '.' to exit.");
  1371.     MoveCursor(&line,&samp);
  1372.  
  1373.     centerline = subsample*(line-sldd) / zoom + sl;
  1374.     centersamp = subsample*(samp-ssdd) / zoom + ss;
  1375.  
  1376.     sprintf (dispstr, "Line : %5d   Sample : %5d", centerline, centersamp);
  1377.     StatusLine(1,dispstr);
  1378. }
  1379.  
  1380. int DoProfile(void)
  1381. /*  DoProfile performs the profile command.
  1382. */
  1383. {
  1384.     DrawBox (dispnl-45, 1, 46, dispns, 0);
  1385.     Profile();
  1386. }
  1387.  
  1388.  
  1389.  
  1390. int StartUp (int argc, char **argv)
  1391. /*  StartUp sets up some things for the main program.
  1392.     The display is turned on, variables initialized, and the
  1393.     welcome message is printed or the file opened instead.
  1394. */
  1395. {
  1396.     int    i;
  1397.     char   *dot_ptr, *batchname;
  1398.     char   f_extension[4];
  1399.     char   temp[40];
  1400.  
  1401.     InitDisplay();
  1402.  
  1403.     OpenFileFlag = 0;
  1404.     nl = 0; ns = 0; sl = 1; ss = 1; sldd = 1; ssdd = 1;
  1405.     subsample = 1; zoom = 1;
  1406.     centerline = -1;  centersamp = -1;  lastsl = 1;   lastss = 1;
  1407.     DNlow = 0;  DNhigh = 255;
  1408.     if ((batchname = getenv("IMBROWSE")) != NULL)
  1409.     {
  1410.         strcpy(BrowseName, batchname);
  1411.         strcat(BrowseName, "BROWSE.CMD");
  1412.         strcpy(SelectName, batchname);
  1413.         strcat(SelectName, "IMDISP.SEL");
  1414.     }
  1415.     if (argc > 1)
  1416.     {
  1417.         if((dot_ptr = strpbrk(argv[1],".")) == NULL)
  1418.         {
  1419.             StatusLine(0,"Illegal command line entry");
  1420.         }
  1421.         dot_ptr++;   /* Move ptr to the extension of the command file */
  1422.         strncpy(f_extension, dot_ptr, 3);   /* Get copy of extension */
  1423.         f_extension[3] = '\0';
  1424.         if (!strcmp(strupr(f_extension),"MNU"))
  1425.         {
  1426.             strcpy (CommandString, "MENU ");
  1427.             strcat (CommandString, argv[1]);
  1428.             DoMenu();
  1429.         }
  1430.         else if (!strcmp(strupr(f_extension),"CMD"))
  1431.         {
  1432.             strcpy (CommandString, "BATCH ");
  1433.             strcat (CommandString, argv[1]);
  1434.             DoBatch();
  1435.         }
  1436.         else
  1437.         {
  1438.         /* default will make the filename an image */
  1439.             strcpy (CommandString, "FILE ");
  1440.             strcat (CommandString, argv[1]);
  1441.             GetFile();
  1442.         }
  1443.     }
  1444.     else
  1445.     {
  1446.         Font (0);
  1447.  
  1448.         DrawText ("Welcome to the Planetary Data System",
  1449.                    30,  0, BigChars, 0, numDN-1);
  1450.         DrawText ("Image Display Program Version v5.6",
  1451.                    56,  0, TextHeight, 0, numDN-1);
  1452.         DrawText ("Copyright (C) 1989, 1990",
  1453.                    80, 35, SmallChars, 0, numDN-1);
  1454.         DrawText ("California Institute of Technology", 
  1455.                    98, 35, SmallChars, 0, numDN-1);
  1456.         DrawText ("Sponsorship under NASA Contract", 
  1457.                    116, 35, SmallChars, 0, numDN-1);
  1458.         DrawText ("NAS7-918 is acknowledged.", 
  1459.                    134, 35, SmallChars, 0, numDN-1);
  1460.         DrawText ("Use HELP SET to see display options.",
  1461.                    150, 35, SmallChars, 0, numDN-1);
  1462.  
  1463.         sprintf( temp, "Allocated %d lines in REFRESH buffer.", RefreshLines);
  1464.         DrawText (temp,
  1465.                   166, 35, SmallChars, 0, numDN-1);
  1466.     }
  1467.  
  1468.     if (argc == 1) StatusLine(1,"Type HELP for help");
  1469. }
  1470.  
  1471. int DoSave(void)
  1472. /* should ask for nl,ns if there is no open image file */
  1473.  
  1474. {
  1475. /* DoSave saves the current display to a disk file */
  1476.  
  1477.     char  filename[128], status[128], dispstr[128];
  1478.     unsigned char *linebuf,*outbuf;
  1479.     int   i,j,k,flag;
  1480.     int   ssl,sss,snl,sns,sbitsperpix; 
  1481.     int   DN;
  1482.     int   defnl, defns;
  1483.     int   dispbits = 1;
  1484.     
  1485.     if (OpenFileFlag == 0) 
  1486.     {
  1487.        StatusLine(0,"Use the \'FILE fname\' command to select image");
  1488.        return;
  1489.     }
  1490.  
  1491.     if (numDN ==  16) dispbits = 4;
  1492.     if (numDN == 256) dispbits = 8;
  1493.     
  1494.     defnl = (dispnl > nl) ? nl : dispnl; /* default nl and ns */
  1495.     defns = (dispns > ns) ? ns : dispns;
  1496.  
  1497.     GetKeywordInteger (CommandString, "SL", 1, &ssl, &flag);
  1498.     GetKeywordInteger (CommandString, "SS", 1, &sss, &flag);
  1499.     GetKeywordInteger (CommandString, "NL", defnl-ssl+1, &snl, &flag);
  1500.     GetKeywordInteger (CommandString, "NS", defns-sss+1, &sns, &flag);
  1501.     GetKeywordInteger (CommandString, "BP", dispbits, &sbitsperpix, &flag);
  1502.     GetKeywordString  (CommandString, "SAV", " ", filename, &flag);
  1503.  
  1504.   /* make sure parameters don't get interpreted as a filemask. */
  1505.     if (strcmp(filename,"SL") == 0 || strcmp(filename,"SS") == 0 ||
  1506.         strcmp(filename,"NL") == 0 || strcmp(filename,"NS") == 0 ||
  1507.         strcmp(filename,"BP") == 0)
  1508.     {
  1509.        BadStatus ("Must give name of image file, (eg. SAVE image.img)");
  1510.        return;
  1511.     }
  1512.  
  1513.     OpenImage (filename, 1, "write", &snl, &sns, &sbitsperpix, status);
  1514.     if (BadStatus (status))
  1515.         return;
  1516.  
  1517.     while ((linebuf = malloc(sns*2)) == NULL)
  1518.        FreeRefresh("linebuf save");
  1519.     while ((outbuf = malloc(sns*2)) == NULL)
  1520.        FreeRefresh("outbuf save");
  1521.     j = 1;
  1522.     for (i = ssl;i < ssl+snl; i++)
  1523.     {
  1524.     /* check here for going off screen */
  1525.        for (k=sss;k < sns+sss; k++)
  1526.        {
  1527.            ReadPixel(i,k,&DN);
  1528.            linebuf[k-sss] = DN;
  1529.        }
  1530.        if (sbitsperpix != 8)
  1531.        {
  1532.            ConvertLine(linebuf,outbuf,8,sbitsperpix,sns,status);
  1533.            WriteLine(1,outbuf,j,1,sns,status);
  1534.        }
  1535.        else
  1536.            WriteLine(1,linebuf,j,1,sns,status);
  1537.        j++; 
  1538.     }
  1539.     free(linebuf); 
  1540.     free(outbuf);  
  1541.     CloseImage(1,status);
  1542. }
  1543.  
  1544. int DoBatch(void)
  1545. {
  1546.     char BatchName[32];
  1547.     int  flag = 0;
  1548.     char buffer[81];
  1549.  
  1550.     GetKeywordString (CommandString, "BAT", "BATCH.CMD", BatchName, &flag);
  1551. /*    ClearDisplay(0); */
  1552.     BatchFile = fopen(BatchName,"r");
  1553.     if (BatchFile == NULL)
  1554.        StatusLine(0,"File not found.");
  1555.     else  
  1556.     {
  1557.     /* check for SFDU labels */
  1558.        BatchFlag = 1;
  1559.        fgets(buffer, 80, BatchFile);
  1560.        if (strnicmp(buffer,"CCSD",4) == 0 ||
  1561.            strnicmp(buffer,"NJPL",4) == 0)
  1562.            do
  1563.            {
  1564.                fgets(buffer,80,BatchFile);
  1565.                if (strnicmp(buffer,"END",3) == 0 &&
  1566.                   (strlen(buffer) <= 5 || buffer[3] == ' '))
  1567.                      break;
  1568.            } while (!feof(BatchFile));
  1569.        else 
  1570.            fseek(BatchFile, 0L, SEEK_SET);
  1571.     }
  1572. }
  1573.  
  1574.  
  1575. int DoLabel(void)
  1576. {
  1577.     FILE   *labels;
  1578.     int    i;
  1579.     char   buffer[81];
  1580.     int    line_count=0;
  1581.     int    ch;
  1582.     int    done;
  1583.  
  1584.     if (OpenFileFlag == 0)
  1585.     {
  1586.        StatusLine(0,"Use the \'FILE fname\' command to select image");
  1587.        return;
  1588.     }
  1589.  
  1590.     ReadPalette(CT);
  1591.     DisplayOff();
  1592.     for (i=0; i<24; i++)
  1593.        printf("\n");
  1594.  
  1595.     if (LabelFileName[0] != NULL)
  1596.        labels = fopen(LabelFileName,"r");
  1597.     else
  1598.     {
  1599.        lseek( FCB[0].handle, 0L, SEEK_SET);
  1600.        labels = fdopen(FCB[0].handle,"r");
  1601.     }
  1602.  
  1603.     done = FALSE;
  1604.     while (!done)
  1605.     {
  1606.        fgets(buffer,81,labels);
  1607.        printf("%s",buffer);
  1608.        line_count++;
  1609.        if (line_count == 22)
  1610.        {
  1611.           printf("\n<< Hit Q to quit, or any other key to continue... >>\n");
  1612.           ch = getch();
  1613.           if ((ch == 81) || (ch == 113)) done = TRUE;
  1614.           printf("\n");
  1615.           line_count=0;
  1616.        }
  1617.        if (feof(labels) || (strnicmp(buffer,"END",3) == 0 &&
  1618.           (strlen(buffer) <= 5 || buffer[3] == ' ')))
  1619.        {
  1620.            done = TRUE;
  1621.            printf( "\n<< Press any key to return to command line >>\n" );
  1622.            getch();
  1623.        }
  1624.     }
  1625.     if (LabelFileName[0] != NULL)
  1626.        fclose(labels);
  1627.  
  1628.     if (!done)
  1629.     {
  1630.       printf( "\n<< Press any key to return to command line >>\n" );
  1631.       getch();
  1632.     }
  1633.     DisplayOn();
  1634.     WritePalette(DefaultPalette);
  1635. }
  1636.  
  1637.  
  1638.  
  1639. int DoMenu(void)
  1640. {
  1641.     FILE   *MenuFile;
  1642.     char   temp[40], string[81], writebuf[81], choice[10], *fileopt[50];
  1643.     int    flag = 0, done = 0, index = 0, toplist = 1, lowlist = PAGELEN;
  1644.     int    charcnt=81, i, numchoice;
  1645.  
  1646.     GetKeywordString(CommandString, "MEN", "MENU.MNU",temp, &flag);
  1647.     if (flag == 1)
  1648.         strcpy(MenuName, temp);
  1649.     if ((MenuFile = fopen(MenuName,"r"))==NULL)
  1650.     {
  1651.        StatusLine(0,"File not found.");
  1652.        return;
  1653.     }
  1654.     fseek(MenuFile, 0L, SEEK_SET);
  1655.     do
  1656.     {
  1657.        fgets(string, charcnt, MenuFile);
  1658.        if (strnicmp(string,"CCSD",4) == 0 ||
  1659.            strnicmp(string,"NJPL",4) == 0)
  1660.        {
  1661.            do
  1662.            {
  1663.                fgets(string,charcnt,MenuFile);
  1664.                if (strnicmp(string,"END",3) == 0 &&
  1665.                   (strlen(string) <= 5 || string[3] == ' ')) break;
  1666.            } while (!feof(MenuFile));
  1667.        fgets(string,charcnt,MenuFile);
  1668.        }
  1669.        for (i = 1; i < 81; i++)
  1670.            if (string[i] == '\n')
  1671.                string[i] = '\0';
  1672.        index += 1;
  1673.        while ((fileopt[index] = malloc(strlen(string)+1))==NULL)
  1674.            FreeRefresh("fileopt");
  1675.        strcpy(fileopt[index],string);
  1676.     } while (!feof(MenuFile));
  1677.  
  1678.     fclose(MenuFile);
  1679.     index--;  /* Take off the END from the menu list */
  1680.  
  1681.     while( !done )
  1682.     {
  1683.        ClearDisplay(0);
  1684.        TextLine = TextHeight + 5; TextSample = 10;
  1685.        WriteText("Menu Selection");
  1686.        if (index < PAGELEN)
  1687.            lowlist = index;
  1688.  
  1689.        for (i = toplist; i <= lowlist; i++)
  1690.        {
  1691.            sprintf( writebuf, "%d) %s", i, fileopt[i]);
  1692.            WriteText(writebuf);
  1693.        }
  1694.        WriteText("Choose: <#>, N(ext page), P(revious page), Q(uit)");
  1695.        TypeText("Option>> ");
  1696.        /*TextLine-=15;*/ TextSample = 90;
  1697.        AcceptText(choice);
  1698.  
  1699.        switch(choice[0])
  1700.        {
  1701.  
  1702.        case 'N':
  1703.        case 'n':
  1704.  
  1705.            toplist = ((toplist + PAGELEN) > index) ? index : toplist + PAGELEN;
  1706.            lowlist = ((toplist + PAGELEN) > index) ? index : toplist + PAGELEN;
  1707.            break;
  1708.  
  1709.        case 'P':
  1710.        case 'p':
  1711.  
  1712.            toplist = ((toplist - PAGELEN) < 1) ? 1 : toplist - PAGELEN;
  1713.            lowlist = ((toplist + PAGELEN) > index) ? index : toplist + PAGELEN-1;
  1714.            break;
  1715.  
  1716.        case 'Q':
  1717.        case 'q':
  1718.  
  1719.            ClearDisplay(0);
  1720.            done = 1;
  1721.            break;
  1722.  
  1723.        default:
  1724.  
  1725.            if (isdigit(choice[0]))
  1726.            {
  1727.                numchoice= atoi(choice);
  1728.                if (numchoice > 0 && numchoice <= index)
  1729.                {
  1730.                    if ((strnicmp(fileopt[numchoice]+
  1731.                         strlen(fileopt[numchoice])-4,".pal",4))== 0)
  1732.                            strcpy(CommandString,"PAL LOAD ");
  1733.  
  1734.                    else if ((strnicmp(fileopt[numchoice]+
  1735.                         strlen(fileopt[numchoice])-4,".cmd",4))== 0)
  1736.                            strcpy(CommandString,"BATCH ");
  1737.                    else
  1738.                        strcpy(CommandString,"FILE ");
  1739.  
  1740.                    strcat( CommandString, fileopt[numchoice]);
  1741.                    flowthru = 1;
  1742.                    done     = 1;
  1743.                    ClearDisplay(0);
  1744.                }
  1745.                else
  1746.                    WriteText("Invalid input!!!!");
  1747.            }
  1748.            break;
  1749.        }
  1750.     }
  1751.     for (i = 1; i <= index+1; i++)
  1752.        free(fileopt[i]);
  1753. }
  1754.  
  1755. int DoPosText(void)
  1756. {
  1757.     char   string[81], dispstr[64], *lquotptr, *fquotptr;
  1758.     int    flag = 0;
  1759.     int    line = 0, samp = 0;
  1760.  
  1761.  
  1762.     GetKeywordInteger (CommandString, "LIN", 0, &line, &flag);
  1763.     GetKeywordInteger (CommandString, "SAM", 0, &samp, &flag);
  1764.     GetKeywordString(CommandString, "TEX", "", string, &flag);
  1765.     if (!flag)
  1766.     {
  1767.        StatusLine(2,"Please enter text:");
  1768.        AcceptText(string);
  1769.        strcpy(dispstr,"Please enter text:");
  1770.        strcat(dispstr,string);
  1771.  
  1772.        LengthText (dispstr, TextHeight, &line);
  1773.        EraseText (TextLine, TextSample, TextHeight, line, 0);
  1774.  
  1775.        DoRefresh();
  1776.     }
  1777.     else
  1778.     {
  1779.        fquotptr = strpbrk(CommandString,"\'\"");
  1780.        lquotptr = strrchr(CommandString,'\'');
  1781.        if (lquotptr == NULL)
  1782.        {
  1783.           lquotptr = strrchr(CommandString,'\"');
  1784.           CommandString[strlen(CommandString)] = NULL;
  1785.        }
  1786.        else
  1787.            strcpy(lquotptr,"\0");
  1788.        strcpy(string,++fquotptr);
  1789.     }
  1790.  
  1791.     if (line == 0 || samp == 0)
  1792.     {
  1793.        StatusLine(1,"Arrow keys move; +,- changes cursor increment; '.' to exit.");
  1794.        MoveCursor(&line,&samp);
  1795.     }
  1796.  
  1797.     TextLine = line - (TextHeight + 0); TextSample = samp;
  1798.     IntoMem = 0;
  1799.     TypeText(string);
  1800.     TextSample = samp;
  1801. /*
  1802.     IntoMem = 1;
  1803.     TypeText(string);
  1804.     DoRefresh();
  1805. */
  1806. }
  1807.  
  1808. int DoOverlay(void)
  1809. {
  1810.     int    dn, grids, i, j, x, y, flag, start, incr, defdn, offset = 0;
  1811.     char   label[20];
  1812.     float  delta, mlat, mlon, hold;
  1813.  
  1814.     if (zoom != 1 || subsample != 1)
  1815.     {
  1816.        StatusLine(0,"Can't overlay zoomed or subsampled images.");
  1817.        return;
  1818.     }
  1819.     if ((strncmp(Object,"^CLOUD_IMAGE",12)  == 0) ||
  1820.         (strncmp(Object,"^MOSAIC_IMAGE",13) == 0))
  1821.     {
  1822.        maxlat =  55.0;
  1823.        maxlon = 140.0;
  1824.        delta  =   5.0;
  1825.        start  =   1;
  1826.        incr   =  71;
  1827.        defdn  = numDN-1;
  1828.     }
  1829.     else
  1830.     {
  1831.        delta = 1.0;
  1832.        start =   7;
  1833.        incr  = 100;
  1834.        defdn =   0;
  1835.     }
  1836.     if (maxlat == 0.0 && minlat == 0.0 && maxlon == 0.0 && minlon == 0.0)
  1837.     {
  1838.         GetKeywordReal (CommandString, "MAXLAT", 0.0, &maxlat, &flag);
  1839.         GetKeywordReal (CommandString, "MAXLON", 0.0, &maxlon, &flag);
  1840.     }
  1841.     if (maxlon < 0.0)
  1842.         maxlon *= -1.0; /* convert to west lon */
  1843.     if (minlon < 0.0)
  1844.         minlon *= -1.0;
  1845.     if (minlon > maxlon)
  1846.     {
  1847.         hold   = maxlon;
  1848.         maxlon = minlon;
  1849.         minlon = hold;
  1850.     }
  1851.  
  1852.     GetKeywordString (CommandString, "LEG", "",label,&flag);
  1853.     if (flag >= 0)
  1854.     {
  1855.        j = 120;
  1856.        hold = -1.0;
  1857.        TextLine = j+8; TextSample = 540;
  1858.        sprintf( label, "%4.1f", hold);
  1859.        WriteText(label);
  1860.        hold += .5;
  1861.        DrawLine( j, 590-5, j++, 610, 35/(256/numDN));
  1862.  
  1863.        for (i=38;i<255;i+=3)
  1864.        {
  1865.            if (i==74 || i==116 || i == 158 || i == 200 || i == 242)
  1866.            {
  1867.                offset = 5;
  1868.                TextLine = j+8; TextSample = 540;
  1869.                sprintf(label,"%4.1f",hold);
  1870.                WriteText(label);
  1871.                hold += .5;
  1872.            }
  1873.            DrawLine( j, 590-offset, j++, 610, i/(256/numDN));
  1874.            DrawLine( j, 590,        j++, 610, i/(256/numDN));
  1875.            offset = 0;
  1876.        }
  1877.        DrawLine( j, 590, j++, 610, 255/(256/numDN));
  1878.        TextLine = j+20; TextSample = 520;
  1879.        strcpy(label,"Pigment");
  1880.        WriteText(label);
  1881.        TextLine = j+40; TextSample = 520;
  1882.        strcpy(label,"Concentratn");
  1883.        WriteText(label);
  1884.        TextLine = j+60; TextSample = 520;
  1885.        strcpy(label,"LOG(mg/m-3)");
  1886.        WriteText(label);
  1887.     }
  1888.     GetKeywordInteger (CommandString, "DN",     0, &dn,     &flag);
  1889.     if (flag <=0)
  1890.        dn = defdn;
  1891.     mlat = maxlat; mlon = maxlon;
  1892.     x = min(ns,dispns); y = min(nl-sl+1,dispnl);
  1893.     if (sl > 1)
  1894.     {
  1895.        if (sl < start)
  1896.            offset = 1-sl;
  1897.        else
  1898.        {
  1899.            i       = sl/incr+1;
  1900.            offset += i * incr - sl + 1;
  1901.            mlat   -= (float)i * delta;
  1902.        }
  1903.     }
  1904.     for (i=start;i<ns;i+=incr)     /* draw x axis */
  1905.     {
  1906.        DrawLine(1,i,y,i,dn);
  1907.        TextLine = start+offset+38; TextSample = i+1;
  1908.        sprintf(label,"%4.0f",mlon);
  1909.        WriteText(label);
  1910.        mlon -= delta;
  1911.     }
  1912.  
  1913.     for (i=start+offset;i<y;i+=incr)     /* draw y axis */
  1914.     {
  1915.        DrawLine(i,1,i,x,dn);
  1916.        TextLine = i+15; TextSample = 8;
  1917.        sprintf(label,"%4.0f",mlat);
  1918.        WriteText(label);
  1919.        mlat -= delta;
  1920.     } 
  1921. }
  1922.  
  1923.  
  1924. int DoSerial(void)
  1925. {
  1926.      TextLine = dispnl;  TextSample = 1;
  1927.      WriteText ("Not implemented yet.");
  1928. }
  1929.  
  1930. int DoPrint(void)
  1931. {
  1932.      TextLine = dispnl;  TextSample = 1;
  1933.      WriteText ("Not implemented yet.");
  1934. }
  1935.  
  1936. int ctrl_c(void)  /* interrupt routine. */
  1937. {
  1938.      DisplayOff();
  1939.      puts("\nUser Aborted\n");
  1940.      exit(2);
  1941.      return(1);
  1942. }
  1943.