home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR23 / TOUCH2.ZIP / DUMP.C < prev    next >
C/C++ Source or Header  |  1993-08-14  |  24KB  |  1,209 lines

  1. /*
  2.  * dump.c - dump the meter's memory
  3.  *
  4.  * V. Abell
  5.  */
  6.  
  7. /*
  8.  * Copyright 1993 Victor A. Abell, Lafayette, Indiana  47906.  All rights
  9.  * reserved.
  10.  *
  11.  * Written by Victor A. Abell.
  12.  *
  13.  * Permission is granted to anyone to use this software for any purpose on
  14.  * any computer system, and to alter it and redistribute it freely, subject
  15.  * to the following restrictions:
  16.  *
  17.  * 1. Victor A. Abell is not responsible for any consequences of the use of
  18.  * this software.
  19.  *
  20.  * 2. The origin of this software must not be misrepresented, either by
  21.  *    explicit claim or by omission.  Credit to Victor A. Abell must
  22.  *    appear in documentation and sources.
  23.  *
  24.  * 3. Altered versions must be plainly marked as such, and must not be
  25.  *    misrepresented as being the original software.
  26.  *
  27.  * 4. This notice may not be removed or altered.
  28.  */
  29. #ifndef lint
  30. static char copyright[] =
  31. "@(#) Copyright 1993 Victor A. Abell.\nAll rights reserved.\n";
  32. #endif
  33.  
  34. #include "touch2.h"
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include "asyncpec.h"
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40.  
  41. #define DUMPNL    256            /* dump number of lines */
  42. #define FIELDLN    16            /* dump field length */
  43. #define    RDYCOL    31            /* ready message column */
  44. #define    SMROW    12            /* status message row */
  45.  
  46. char CksumErrMsg[64];            /* checksum error message */
  47. char Date[FIELDLN];            /* dump line date */
  48. char Dow[FIELDLN];            /* dump line day of week */
  49. int DumpHs = 0;                /* dump header status */
  50. int DumpLc = 0;                /* number of dump lines */
  51. char DumpfnQ[DUMPFNL];            /* QuattroPro dump file name */
  52. char DumpfnR[DUMPFNL];            /* raw dump file name */
  53. FILE *Dumpfs = NULL;            /* write dump file stream */
  54. char DumpLine[DUMPLL+1];        /* dump line */
  55. char *DumpLp[DUMPNL];            /* dump line pointers */
  56. char Graphfn[DUMPFNL];            /* graph file name */
  57. FILE *Graphfs = NULL;            /* graph file stream */
  58. FILE *Rdumpfs = NULL;            /* read dump file stream */
  59. short Rtype;                /* dump line reading type */
  60. char Time[FIELDLN];            /* dump line time */
  61.  
  62.  
  63. struct menu DumpErr[] = {
  64.     { 12, 20, DumpLine },
  65.     {  0,  0, NULL },
  66. };
  67.  
  68. struct menu DumpRdy[] = {
  69.     { 12, RDYCOL, "Waiting on meter" },
  70.     {  0,  0, NULL },
  71. };
  72.  
  73. struct menu DumpSt[] = {
  74.     { 12, 27, "Waiting for meter to start dump" },
  75.     {  0,  0, NULL },
  76. };
  77.  
  78. #define    TYPEBUFL    64
  79. char CheckDump[TYPEBUFL];
  80. char DumpFile[TYPEBUFL];
  81. char DumpScreen[TYPEBUFL];
  82. char EraseBuf[TYPEBUFL];
  83. char FormatBuf[TYPEBUFL];
  84. char GraphBuf[TYPEBUFL];
  85. char GraphTtl[GTTLLNL+2+1];
  86. char ReadBuf[TYPEBUFL];
  87.  
  88. struct menu DumpType[] = {
  89.     {  2, 10, CheckDump },
  90. #define    CKDMPLN    0
  91.     {  4, 10, EraseBuf },
  92.     {  6, 10, DumpFile },
  93. #define FILLN    2
  94.     {  8, 10, GraphBuf },
  95. #define    GRAPHLN    3
  96.     { 10, 10, FormatBuf },
  97. #define    FMTLN    4
  98.     { 12, 10, ReadBuf },
  99. #define READLN    5
  100.     { 14, 10, DumpScreen },
  101. #define SCRLN    6
  102.     { 16, 10, "T - change graph title from:" },
  103.     { 17, 12,  GraphTtl},
  104.     { 19, 10, "X - eXit"},
  105.     {  0,  0, NULL },
  106. };
  107.  
  108. struct menu GraphType[] = {
  109.     { 12, 30, "F - write graph to file" },
  110.     { 14, 30, "S - draw graph on screen" },
  111.     {  0,  0, NULL },
  112. };
  113.  
  114. static int CheckCksum(int len);
  115. static void DispDumpLns();
  116. static void EraseDump();
  117.  
  118. #if    defined(UNIX)
  119. static int GetDispLn(char *s, int n);
  120. #else
  121. static int GetDispLn(char *s, short n);
  122. #endif
  123.  
  124. static int CheckFileNm(char *fn);
  125. static int GetDumpType(char *ty);
  126. static void RcvErr(int err);
  127. static void ReadDump();
  128. static int StoreDumpLn();
  129. static void TrimSpaces(char *s);
  130. static void WarnCantOpen(char *f);
  131.  
  132. #ifdef    UNIX
  133. static int WarnCksum(int f);
  134. #else
  135. static int WarnCksum(short f);
  136. #endif
  137.  
  138. static int WarnDumpHdr();
  139. static void WarnDumpLen();
  140. static int WarnExist(char *d, struct stat *s);
  141. static void WrDumpF();
  142.  
  143.  
  144. /*
  145.  * CheckCksum() - check checksum
  146.  */
  147.  
  148.  
  149. static int
  150. CheckCksum(len)
  151.     int len;            /* length of line in DumpLine */
  152. {
  153.     char cksum[5];
  154.     short i;
  155.     unsigned int sum;
  156.  
  157.     if (Cksum) {
  158.         if (len < 5) {
  159.             (void) strcpy(CksumErrMsg, "Record is too short.");
  160.             return(1);
  161.         }
  162.     /*
  163.      * A leading 'P' has been stripped from all dump header records,
  164.      * and a leading "P " has been stripped from dump file records.
  165.      * They need to be considered in computing the checksum.
  166.      */
  167.         if (DumpLc == 0)
  168.             sum = (unsigned int) 'P';
  169.         else {
  170.             if (DumpLine[0] == 'P')
  171.                 sum = 0;
  172.             else 
  173.                 sum = (unsigned int) 'P' + (unsigned int) ' ';
  174.         }
  175.         for (i = 0; i < (len - 5); i++)
  176.             sum += (unsigned int) DumpLine[i];
  177.         (void) sprintf(cksum, "%04x", sum);
  178.         if (strcmpi(&DumpLine[len - 4], cksum) == 0)
  179.             return(0);
  180.         for (i = 0; cksum[i]; i++) {
  181.             if (isalpha(cksum[i]) && islower(cksum[i]))
  182.                 cksum[i] = toupper(cksum[i]);
  183.         }
  184.         (void) sprintf(CksumErrMsg, "Computed %s; read %s.",
  185.             cksum, &DumpLine[len - 4]);
  186.         return(1);
  187.     }
  188.     return(0);
  189. }
  190.  
  191.  
  192. /*
  193.  * CheckESC() - check for ESC
  194.  */
  195.  
  196. int
  197. CheckESC()
  198. {
  199.     int ch;
  200.  
  201.     if (kbhit()) {
  202.         if ((ch = getch()) == 0)
  203.             ch = getch();
  204.         if (ch == ESC)
  205.             return(1);
  206.         putch(BELL);
  207.     }
  208.     return(0);
  209. }
  210.  
  211.  
  212. /*
  213.  * CheckFilNm() - check file name
  214.  */
  215.  
  216. static int
  217. CheckFileNm(fn)
  218.     char *fn;            /* file name to check */
  219. {
  220.     char *cp;
  221.     short err = 0;
  222.     short fnl;
  223.     short lc, p, rc;
  224.     char *mp, msg[80];
  225.  
  226. /*
  227.  * Skip leading alpha, followed by a colon -- i.e., a drive specification.
  228.  */
  229.     fnl = strlen(fn);
  230.     if (fnl > 1 && isalpha(*fn) && fn[1] == ':')
  231.         cp = fn + 2;
  232.     else
  233.         cp = fn;
  234. /*
  235.  * Check the file path components -- i.e., those between / and \.
  236.  *
  237.  * The left part (the name) may have no more than 8 characters.
  238.  * The right part (the extension) may have no more than 3 characters.
  239.  * There may be one period, separating the name and extension.
  240.  * The characters must be alphanumeric or special characters from the set:
  241.  *
  242.  *    _ ^ $ ~ ! # % & - { } @ ` ' ( )
  243.  */
  244.     (void) strcpy(msg, "has ");
  245.     mp = &msg[strlen(msg)];
  246.     while (err == 0 && *cp) {
  247.         if (*cp == '/' || *cp == '\\') {
  248.             cp++;
  249.         continue;
  250.         }
  251.         lc = p = rc = 0;
  252.         while (*cp) {
  253.         switch (*cp) {
  254.         /*
  255.          * These are the legal special characters.
  256.          */
  257.         case '_':
  258.         case '^':
  259.         case '$':
  260.         case '~':
  261.         case '!':
  262.         case '#':
  263.         case '%':
  264.         case '&':
  265.         case '-':
  266.         case '{':
  267.         case '}':
  268.         case '@':
  269.         case '`':
  270.         case '\'':
  271.         case ')':
  272.         case '(':
  273.             break;
  274.         /*
  275.          * The / and \ end a component.
  276.          */
  277.         case '/':
  278.         case '\\':
  279.             err = -1;
  280.             break;
  281.         /*
  282.          * The period separates the name and extension.
  283.          */
  284.         case '.':
  285.             if (p) {
  286.             (void) strcpy(mp, "more than one period.");
  287.             err = 1;
  288.             } else if (lc == 0) {
  289.             (void) strcpy(mp,
  290.                 "nothing to the left of the period.");
  291.             err = 1;
  292.             break;
  293.             } else
  294.             p = 1;
  295.             break;
  296.         /*
  297.          * Letters (either case) and numbers are legal.
  298.          */
  299.         default:
  300.             if (isalnum(*cp))
  301.             break;
  302.             (void) strcpy(mp, "an illegal character.");
  303.             err = 1;
  304.         }
  305.         /*
  306.          * Stop on error or end of component.  Skip a period.
  307.          */
  308.         if (err)
  309.             break;
  310.         if (*cp++ == '.')
  311.             continue;
  312.         /*
  313.          * The name may have 8 characters; the extension, 3.
  314.          */
  315.         if ( ! p) {
  316.             if (lc > 7) {
  317.             (void) strcpy(mp,
  318.                 "more than 8 characters in the name part.");
  319.             err = 1;
  320.             } else
  321.             lc++;
  322.         } else {
  323.             if (rc > 2) {
  324.             (void) strcpy(mp,
  325.                 "more than 3 characters in the extension.");
  326.             err = 1;
  327.             } else
  328.             rc++;
  329.         }
  330.         }
  331.     /*
  332.      * Continue after the end of a component; stop on an error.
  333.      */
  334.         if (err == -1) {
  335.         err = 0;
  336.         continue;
  337.         }
  338.         if (err)
  339.         break;
  340.     }
  341. /*
  342.  * Return if no error; warn if there was one.
  343.  */
  344.     if (err == 0)
  345.         return(0);
  346.     (void) WarnMsg(11, (short)((Vc.numtextcols - fnl)/2 + 1), fn,
  347.         13, (short)((Vc.numtextcols - strlen(msg))/2 + 1), msg, 0);
  348.     return(1);
  349. }
  350.  
  351.  
  352. /*
  353.  * DumpMtr() - dump the meter's memory
  354.  */
  355.  
  356. void
  357. DumpMtr()
  358. {
  359.     int err, i, len;
  360.     char dt, msg[32];
  361.  
  362.     if (GetDumpType(&dt) == 0)
  363.         return;
  364.     if ( ! DumpLc && dt != 'r') {
  365.         for (;;) {
  366.         if (WaitRdy() == 0) {
  367.             CloseDump();
  368.             return;
  369.         }
  370.         DispMenu(DumpSt, NULL);
  371.         if (WaitCmd("DMP", 'P') == 0) {
  372.             (void) strcpy(DumpLine, "Dump command failed.");
  373.             DispMenu(DumpErr,
  374.                 "Press ESC to exit; any other key to retry.");
  375.             if ((char)WaitAnyKey() == ESC) {
  376.                 CloseDump();
  377.                 return;
  378.             }
  379.             continue;
  380.         }
  381.         _clearscreen(_GCLEARSCREEN);
  382.         PromptMsg("Press ESC to exit.");
  383.         len = GetDataLn(DumpLine, DUMPLL);
  384.         if (CheckCksum(len)) {
  385.             (void) WarnCksum(2);
  386.             CloseDump();
  387.             (void) EraseDump();
  388.             return;
  389.         }
  390.         if (StoreDumpLn()) {
  391.             CloseDump();
  392.             (void) EraseDump();
  393.             return;
  394.         }
  395.         if ( ! ParseHdr()) {
  396.             if ((char)WarnDumpHdr() == ESC) {
  397.                 CloseDump();
  398.                 (void) EraseDump();
  399.                 return;
  400.             }
  401.         }
  402.         _settextposition(SMROW, RDYCOL);
  403.         _outtext("Header record read.");
  404.         for (i = 0;;) {
  405.             if (CheckESC()) {
  406.                 CloseDump();
  407.                 (void) EraseDump();
  408.                 return;
  409.             }
  410.             len = GetDataLn(DumpLine, DUMPLL);
  411.             if (DumpLine[0] != 'P')
  412.                 break;
  413.             if (CheckCksum(len)) {
  414.                 (void) WarnCksum(2);
  415.                 CloseDump();
  416.                 (void) EraseDump();
  417.                 return;
  418.             }
  419.             if (StoreDumpLn()) {
  420.                 CloseDump();
  421.                 (void) EraseDump();
  422.                 return;
  423.             }
  424.             if (i == 0) {
  425.                 ClearRow(SMROW, RDYCOL);
  426.                 (void) sprintf(msg,
  427.                     "Record %3d read.", DumpLc - 1);
  428.                 _settextposition(SMROW, RDYCOL);
  429.                 i = 1;
  430.             } else {
  431.                 _settextposition(SMROW, RDYCOL+7);
  432.                 (void) sprintf(msg, "%3d", DumpLc - 1);
  433.             }
  434.             _outtext(msg);
  435.         }
  436.         if (Ndump+1 != DumpLc)
  437.             WarnDumpLen();
  438.         break;
  439.         }
  440.     }
  441.     switch (dt) {
  442.     case 'f':
  443.         WrDumpF();
  444.         break;
  445.     case 'g':
  446.     case 'G':
  447.         DrawGraph((dt == 'g') ? 0 : 1);
  448.         break;
  449.     case 'r':
  450.         ReadDump();
  451.         break;
  452.     case 's':
  453.         DispDumpLns();
  454.     }
  455. }
  456.  
  457.  
  458. /*
  459.  * DispDumpLns() - display dump lines
  460.  */
  461.  
  462. static void
  463. DispDumpLns()
  464. {
  465.     char *bf, bot[80], *cp;
  466.     int cpl, i, j, k, l, lps;
  467.  
  468.     if (DumpLc == 0)
  469.         return;
  470.     cpl = Vc.numtextcols;
  471.     lps = Vc.numtextrows;
  472.     if ((bf = (char *)malloc((size_t)(cpl + 1))) == NULL) {
  473.         _clearscreen(_GCLEARSCREEN);
  474.         _settextposition(12, 20);
  475.         _outtext("DispDump: no temporary line space");
  476.         return;
  477.     }
  478.  
  479.     i = 0;
  480.     for (;;) {
  481.  
  482.     /*
  483.      * Display a screenload.
  484.      */
  485.         _clearscreen(_GCLEARSCREEN);
  486.         for (j = 1; j < lps && (i+j-1) < DumpLc;  j++) {
  487.             for (cp = DumpLp[i+j-1], k = 0; k < cpl; cp++) {
  488.                 if (*cp == '"')
  489.                     continue;
  490.                 if (*cp == '\0')
  491.                     break;
  492.                 bf[k++] = *cp;
  493.             }
  494.             bf[k] = '\0';
  495.             _settextposition(j, 1);
  496.             _outtext(bf);
  497.         }
  498.         (void) sprintf(bot,
  499.           "(%d of %d) Press ESC or X to exit; Page Up/Down; Arrow Up/Down.",
  500.           i+1, DumpLc);
  501.         PromptMsg(bot);
  502.     /*
  503.      * Wait for a command.
  504.      */
  505.         for (k = 1; k;) {
  506.             switch((char)WaitAnyKey()) {
  507.             case ESC:
  508.             case 'x':
  509.             case 'X':
  510.                 return;
  511.             case PGDN:
  512.                 if ((i + lps - 1) < DumpLc) {
  513.                     i += lps - 1;
  514.                     k = 0;
  515.                 } else
  516.                     putch(BELL);
  517.                 break;
  518.             case PGUP:
  519.                 if (i > 0) {
  520.                     i -= lps - 1;
  521.                     if (i < 0)
  522.                         i = 0;
  523.                     k = 0;
  524.                 } else
  525.                     putch(BELL);
  526.                 break;
  527.             case UARW:
  528.                 if (i > 0) {
  529.                     i--;
  530.                     k = 0;
  531.                 } else
  532.                     putch(BELL);
  533.                 break;
  534.             case DARW:
  535.                 if (i < (DumpLc - 1)) {
  536.                     i++;
  537.                     k = 0;
  538.                     break;
  539.                 }
  540.                 /* fall through */
  541.             default:
  542.                 putch(BELL);
  543.             }
  544.         }
  545.     }
  546.  
  547.  
  548. /*
  549.  * EraseDump() -- erase dump
  550.  */
  551.  
  552. static void
  553. EraseDump()
  554. {
  555.     int i;
  556.  
  557.     for (i = 0; i < DumpLc; i++) {
  558.         (void) free(DumpLp[i]);
  559.         DumpLp[i] = NULL;
  560.     }
  561.     DumpLc = Ndump = 0;
  562. }
  563.  
  564.  
  565. /*
  566.  * GetDataLn(s, n) - get meter data line
  567.  */
  568.  
  569. int
  570. GetDataLn(s, n)
  571.     char *s;
  572.     int n;
  573. {
  574.     char c, msg[128];
  575.     int err, i;
  576.  
  577.     for (i = 0;;) {
  578.         if (CheckESC()) {
  579.             s[0] = '\0';
  580.             return(0);
  581.         }
  582.         (void) check_com(&c, &err);
  583.         if ( ! err && c) {
  584.             if (c == CR)
  585.                 break;
  586.             if (c == LF)
  587.                 continue;
  588.             if (i+1 >= n)
  589.                 break;
  590.             s[i++] = c;
  591.         } else if (err == 6)
  592.             continue;
  593.         else if (err)
  594.             RcvErr(err);
  595.     }
  596.     s[i] = '\0';
  597.     return(i);
  598. }
  599.  
  600.  
  601. /*
  602.  * GetDumpType() - get dump type
  603.  */
  604.  
  605. static int
  606. GetDumpType(ty)
  607.     char *ty;            /* type response */
  608. {
  609.     char ch, fn[DUMPFNL];
  610.     short i, m;
  611.     struct stat sbuf;
  612.  
  613.     Dumpfs = Graphfs = NULL;
  614.     for (m = 0;;) {
  615.         if ( ! m) {
  616.             (void) sprintf(FormatBuf,
  617.             "Q - change dump format to %s from %s",
  618.             Qp ? "raw" : "QuattroPro",
  619.             Qp ? "QuattroPro" : "raw");
  620.             if (Qp)
  621.             (void) sprintf(CheckDump,
  622.                     "C - %sdump check, error, and high readings",
  623.                 Ckdump ? "" : "don't ");
  624.             else
  625.             CheckDump[0] = '\0';
  626.             if (DumpLc) {
  627.             (void) sprintf(EraseBuf,
  628.                 "E - erase %d records from dump buffer",
  629.                 DumpLc);
  630.             (void) sprintf(DumpFile,
  631.                 "F - dump %d records to file", DumpLc);
  632.             (void) sprintf(GraphBuf,
  633.                 "G - graph %d records", DumpLc);
  634.             ReadBuf[0] = '\0';
  635.             (void) sprintf(DumpScreen,
  636.                 "S - dump %d records to screen", DumpLc);
  637.             } else {
  638.             EraseBuf[0] = '\0';
  639.             (void) strcpy(DumpFile, "F - dump to file");
  640.             (void) strcpy(GraphBuf, "G - graph");
  641.             (void) strcpy(ReadBuf, "R - read from file");
  642.             (void) strcpy(DumpScreen, "S - dump to screen");
  643.             }
  644.             if (Gttl[0] != '\0') {
  645.             if (ExpandTtl())
  646.                 (void) sprintf(GraphTtl, "Error: %s",
  647.                     TtlErrMsg);
  648.             else
  649.                 (void) sprintf(GraphTtl, "\"%s\"", Exttl);
  650.             } else
  651.             GraphTtl[0] = '\0';
  652.             DispMenu(DumpType, NULL);
  653.             m = 1;
  654.         }
  655.         switch((char)WaitAnyKey()) {
  656.  
  657.         case 'x':
  658.         case 'X':
  659.         case ESC:
  660.             return(0);
  661.         case 'c':
  662.         case 'C':
  663.             Ckdump = Ckdump ? 0 : 1;
  664.             m = 0;
  665.             break;
  666.         case 'e':
  667.         case 'E':
  668.             if ( ! DumpLc)
  669.                 putch(BELL);
  670.             else {
  671.                 (void) EraseDump();
  672.                 m = 0;
  673.             }
  674.             break;
  675.         case 'f':
  676.         case 'F':
  677.             (void) strcpy(fn, Qp ? DumpfnQ : DumpfnR);
  678.             if (GetInp(21, 5, "Name?", fn, fn, sizeof(fn)) == 0)
  679.                 return(0);
  680.             if (CheckFileNm(fn)) {
  681.                 m = 0;
  682.                 break;
  683.             }
  684.             if (stat(fn, &sbuf) == 0) {
  685.                 if (WarnExist(fn, &sbuf) == 0)
  686.                     return(0);
  687.             }
  688.             if ((Dumpfs = fopen(fn, "w+t")) != NULL) {
  689.                 (void) strcpy(Qp ? DumpfnQ : DumpfnR, fn);
  690.                 *ty = 'f';
  691.                 return(1);
  692.             }
  693.             WarnCantOpen(fn);
  694.             m = 0;
  695.             break;
  696.         case 'g':
  697.         case 'G':
  698.             DispMenu(GraphType, NULL);
  699.             if ((ch = (char)WaitAnyKey()) == ESC)
  700.                 return(0);
  701.             switch (ch) {
  702.             case 'f':
  703.             case 'F':
  704.                 (void) strcpy(fn, Graphfn);
  705.                 if (GetInp(21, 5, "Name?", fn, fn, sizeof(fn))
  706.                 == 0)
  707.                     return(0);
  708.                 if (CheckFileNm(fn))
  709.                     break;
  710.                 if (stat(fn, &sbuf) == 0) {
  711.                     if (WarnExist(fn, &sbuf) == 0)
  712.                         return(0);
  713.                 }
  714.                 if ((Graphfs = fopen(fn, "w+t")) != NULL) {
  715.                     (void) strcpy(Graphfn, fn);
  716.                     *ty = 'G';
  717.                     return(1);
  718.                 }
  719.                 WarnCantOpen(fn);
  720.                 break;
  721.             case 's':
  722.             case 'S':
  723.                 *ty = 'g';
  724.                 return(1);
  725.             default:
  726.                 putch(BELL);
  727.             }
  728.             m = 0;
  729.             break;
  730.         case 'q':
  731.         case 'Q':
  732.             Qp = (Qp == 1) ? 0 : 1;
  733.             m = 0;
  734.             break;
  735.         case 'r':
  736.         case 'R':
  737.             (void) strcpy(fn, DumpfnR);
  738.             if (GetInp(21, 5, "Name?", fn, fn, sizeof(fn)) == 0)
  739.                 return(0);
  740.             if (CheckFileNm(fn)) {
  741.                 m = 0;
  742.                 break;
  743.             }
  744.             if ((Rdumpfs = fopen(fn, "r+t")) != NULL) {
  745.                 (void) strcpy(DumpfnR, fn);
  746.                 *ty = 'r';
  747.                 return(1);
  748.             }
  749.             WarnCantOpen(fn);
  750.             m = 0;
  751.             break;
  752.         case 's':
  753.         case 'S':
  754.             *ty = 's';
  755.             return(1);
  756.         case 't':
  757.         case 'T':
  758.             if (GetInp(21, 7, "Title?", Gttl, GraphTtl, GTTLLNL)
  759.             == 0)
  760.                 return(0);
  761.             (void) strcpy(Gttl, GraphTtl);
  762.             m = 0;
  763.             break;
  764.         default:
  765.             putch(BELL);
  766.         }
  767.     }
  768. }
  769.  
  770.  
  771. /*
  772.  * InitDump() - initialize dump
  773.  */
  774.  
  775. void
  776. InitDump()
  777. {
  778.     (void) strcpy(DumpfnQ, DEFQDMPF);
  779.     (void) strcpy(DumpfnR, DEFRDMPF);
  780.     (void) strcpy(Graphfn, DEFGRAPHF);
  781. }
  782.  
  783.  
  784.  
  785. /*
  786.  * GetDispLn(s) - get meter display line
  787.  */
  788.  
  789. static int
  790. GetDispLn(s, n)
  791.     char *s;            /* destination buffer */
  792.  
  793. #if    defined(UNIX)
  794.     int n;                /* destination buffer length */
  795. #else
  796.     short n;            /* destination buffer length */
  797. #endif
  798.  
  799. {
  800.     char c;
  801.     int err, i;
  802.  
  803.     for (i = 0;;) {
  804.         if (CheckESC()) {
  805.             s[0] = '\0';
  806.             return(0);
  807.         }
  808.         (void) check_com(&c, &err);
  809.         if ( ! err && c) {
  810.             if (c == CR) {
  811.                 s[i] = '\0';
  812.                 return(1);
  813.             }
  814.             if (i < n - 1)
  815.                 s[i++] = c;
  816.             else {
  817.                 s[i] = '\0';
  818.                 return(0);
  819.             }
  820.         } else if (err == 6)
  821.             continue;
  822.         else if (err) {
  823.             RcvErr(err);
  824.             return(0);
  825.         }
  826.     }
  827. }
  828.  
  829.  
  830. /*
  831.  * Rcverr() - handle receive error
  832.  */
  833.  
  834. static void
  835. RcvErr(err)
  836.     int err;
  837. {
  838.     char msg[64];
  839.  
  840.     (void) sprintf(msg, "Meter receive error %d", err);
  841.     _clearscreen(_GCLEARSCREEN);
  842.     _settextposition(12, 20);
  843.     _outtext(msg);
  844. }
  845.  
  846.  
  847. /*
  848.  * ReadDump() - read dump from file
  849.  */
  850.  
  851. static void
  852. ReadDump()
  853. {
  854.     char *cp, *rv;
  855.     int i, len;
  856.     short err = 0;
  857.  
  858. /*
  859.  * Read, parse and store the dump header line.
  860.  */
  861.     if ((rv = fgets(DumpLine, DUMPLL, Rdumpfs)) != NULL) {
  862.         if ((cp = strrchr(DumpLine, '\n')) != NULL) {
  863.             *cp = '\0';
  864.             len = cp - DumpLine;
  865.         } else {
  866.             DumpLine[DUMPLL-1] = '\0';
  867.             len = strlen(DumpLine);
  868.         }
  869.         if (CheckCksum(len)) {
  870.             if ((char)WarnCksum(1) == ESC) {
  871.                 CloseDump();
  872.                 (void) EraseDump();
  873.                 return;
  874.             }
  875.         }
  876.         if (StoreDumpLn()) {
  877.             CloseDump();
  878.             (void) EraseDump();
  879.             return;
  880.         }
  881.     } else {
  882.         DumpLine[0] = '\0';
  883.         len = 0;
  884.     }
  885.     if (rv == NULL || ! ParseHdr()) {
  886.  
  887.     /*
  888.      * Handle bad dump header line.
  889.      */
  890.         i = WarnDumpHdr();
  891.         if (DumpLc)
  892.             (void) EraseDump();
  893.         if ((char)i == ESC) {
  894.             CloseDump();
  895.             return;
  896.         }
  897.         err = 1;
  898.     }
  899. /*
  900.  * Read and store the dump lines.
  901.  */
  902.     while (fgets(DumpLine, DUMPLL, Rdumpfs) != NULL) {
  903.         if ((cp = strrchr(DumpLine, '\n')) != NULL) {
  904.             *cp = '\0';
  905.             len = cp - DumpLine;
  906.         } else {
  907.             DumpLine[DUMPLL-1] = '\0';
  908.             len = strlen(DumpLine);
  909.         }
  910.         if (CheckCksum(len)) {
  911.             if ((char)WarnCksum(1) == ESC) {
  912.                 CloseDump();
  913.                 (void) EraseDump();
  914.                 return;
  915.             }
  916.         }
  917.         if (StoreDumpLn()) {
  918.             err = 1;
  919.             break;
  920.         }
  921.     }
  922.     CloseDump();
  923.     if (err == 0 && (Ndump+1 != DumpLc))
  924.         WarnDumpLen();
  925. }
  926.  
  927.  
  928. /*
  929.  * StoreDumpLn() - store dump line via DumpLp[]
  930.  */
  931.  
  932. static int
  933. StoreDumpLn()
  934. {
  935.     char *cp;
  936.     int i;
  937.     size_t l;
  938.     char msg[128];
  939.  
  940.     if (DumpLc >= DUMPNL) {
  941.         (void) sprintf(msg, "Dump buffer is full (limit = %d).",
  942.             DUMPNL);
  943. store_warn:
  944.         i = WarnMsg(12, (short)(((Vc.numtextcols - strlen(msg))/2)+1),
  945.             msg, 14, (short)(((Vc.numtextcols - strlen(DumpLine))/2)+1),
  946.             DumpLine, 1);
  947.         return(((char)i == ESC) ? 1 : 0);
  948.     }
  949.     cp = DumpLine;
  950.     if (*cp == 'P') {
  951.         cp++;
  952.         if (*cp == ' ')
  953.             cp++;
  954.     }
  955.     l = (size_t)(strlen(cp) + 1);
  956.     if ((DumpLp[DumpLc] = (char *)malloc(l)) == NULL) {
  957.         (void) sprintf(msg, "No memory for dump line number %d.",
  958.             DumpLc);
  959.         goto store_warn;
  960.     }
  961.     (void) strcpy(DumpLp[DumpLc], cp);
  962.     DumpLc++;
  963.     return(0);
  964. }
  965.  
  966.  
  967. /*
  968.  * WaitRdy() - wait for the meter to become ready
  969.  */
  970.  
  971. int
  972. WaitRdy()
  973. {
  974.     char buf[16];
  975.     int r;
  976.  
  977.     DispMenu(DumpRdy, NULL);
  978.     OpenCom();
  979.     reset_buffer();
  980.     for (;;) {
  981.         if (CheckESC())
  982.             return(0);
  983.         if (buffer_length == 0)
  984.             continue;
  985.         if (GetDispLn(buf, sizeof(buf)) == 0)
  986.             return(0);
  987.         if (strcmp(buf, "INSERT")  == 0        /* ENGL */
  988.         ||  strcmp(buf, "INSERT.") == 0        /* ESPAN */
  989.         ||  strcmp(buf, "INSER. ") == 0        /* FRANC and ITALI */
  990.         ||  strcmp(buf, "IN    ")  == 0        /* NEDER */
  991.         ||  strcmp(buf, "INSIRA")  == 0        /* PORT */
  992.         ||  strcmp(buf, "SATTIN")  == 0        /* SVENS */
  993.         ||  strcmp(buf, "EINLEG")  == 0        /* DEUTS */
  994.         ||  strcmp(buf, ")))   ")  == 0)    /* SYMB */
  995.             break;
  996.     }
  997.     return(GetDispLn(buf, sizeof(buf)));
  998. }
  999.  
  1000.  
  1001. /*
  1002.  * TrimSpaces() - trim leading and trailing spaces from string
  1003.  */
  1004.  
  1005. static void
  1006. TrimSpaces(s)
  1007.     char *s;            /* string address */
  1008. {
  1009.     char *s1, *s2;
  1010.  
  1011.     for (s1 = s2 = s; *s1; s1++) {
  1012.         if (s2 > s || *s1 != ' ')
  1013.             *s2++ = *s1;
  1014.     }
  1015.     while (s2 > s) {
  1016.         if (*(s2 - 1) != ' ')
  1017.             break;
  1018.         s2--;
  1019.     }
  1020.     *s2 = '\0';
  1021. }
  1022.  
  1023.  
  1024. /*
  1025.  * WarnCantOpen() - issue can't open file warning
  1026.  */
  1027.  
  1028. static void
  1029. WarnCantOpen(f)
  1030.     char *f;            /* file name */
  1031. {
  1032.     char msg[80];
  1033.  
  1034.     (void) sprintf(msg, "Can't open %s", f);
  1035.     (void) WarnMsg(12, 1, msg, 0, 0, NULL, 0);
  1036. }
  1037.  
  1038.  
  1039. /*
  1040.  * WarnCksum()
  1041.  */
  1042.  
  1043. static int
  1044. WarnCksum(f)
  1045.  
  1046. #ifdef    UNIX
  1047.     int f;            /* prompt flag for WarnMsg() */
  1048. #else
  1049.     short f;        /* prompt flag for WarnMsg() */
  1050. #endif
  1051.  
  1052. {
  1053.     char m1[80], m2[80];
  1054.  
  1055.     (void) strcpy(m1, "Checksum doesn't match for dump ");
  1056.     if (DumpLc)
  1057.         (void) sprintf(m2, "record %d.  ", DumpLc);
  1058.     else
  1059.         (void) strcpy(m2, "header record.  ");
  1060.     (void) strcat(m1, m2);
  1061.     (void) strcat(m1, CksumErrMsg);
  1062.     return(WarnMsg(12, (short)(((Vc.numtextcols - strlen(m1))/2)+1), m1,
  1063.         14, (short)(((Vc.numtextcols - strlen(DumpLine))/2)+1),
  1064.         DumpLine, f));
  1065. }
  1066.  
  1067.  
  1068. /*
  1069.  * WarnDumpHdr()
  1070.  */
  1071.  
  1072. static int
  1073. WarnDumpHdr()
  1074. {
  1075.     return(WarnMsg(12, 30, "Bad dump header line:", 14,
  1076.         (short)(((Vc.numtextcols - strlen(DumpLine))/2)+1),
  1077.         DumpLine, 1));
  1078. }
  1079.  
  1080.  
  1081. /*
  1082.  * WarnDumpLen() - warn about incorrect dump length
  1083.  */
  1084.  
  1085. static void
  1086. WarnDumpLen()
  1087. {
  1088.     char msg[80];
  1089.  
  1090.     (void) sprintf(msg,
  1091.         "Dump length incorrect: %d records expected, %d received.",
  1092.         Ndump, DumpLc - 1);
  1093.     (void) WarnMsg(12, 11, msg, 0, 0, NULL, 0);
  1094. }
  1095.  
  1096.  
  1097. /*
  1098.  * WarnExist() - warn that the dump file exists
  1099.  */
  1100.  
  1101. static int
  1102. WarnExist(d, s)
  1103.     char *d;            /* dump file name */
  1104.     struct stat *s;            /* stat buffer */
  1105. {
  1106.     char msg[80];
  1107.  
  1108.     _clearscreen(_GCLEARSCREEN);
  1109.     (void) sprintf(msg, "%s exists.", d);
  1110.     _settextposition(11, (short)((Vc.numtextcols - strlen(msg))/2 + 1));
  1111.     _outtext(msg);
  1112.     (void) sprintf(msg, "It is %ld bytes long.", s->st_size);
  1113.     _settextposition(13, (short)((Vc.numtextcols - strlen(msg))/2 + 1));
  1114.     _outtext(msg);
  1115.     PromptMsg("Press ESC to exit; any other key to overwrite.");
  1116.     if ((char)WaitAnyKey() == ESC)    
  1117.         return(0);
  1118.     return(1);
  1119. }
  1120.  
  1121.  
  1122. /*
  1123.  * WarnMsg() - issue warning message
  1124.  */
  1125.  
  1126. int
  1127. WarnMsg(r1, c1, m1, r2, c2, m2, f)
  1128.  
  1129. #if    defined(UNIX)
  1130.     int r1;                /* first message row */
  1131.     int c1;                /* first message column */
  1132.     char *m1;            /* first message */
  1133.     int r2;                /* second message row */
  1134.     int c2;                /* second message column */
  1135.     char *m2;            /* second message */
  1136.     int f;                /* prompt flag: 0 = any continue
  1137.                      *        1 = ESC abort
  1138.                      *        2 = any abort */
  1139. #else
  1140.     short r1;            /* first message row */
  1141.     short c1;            /* first message column */
  1142.     char *m1;            /* first message */
  1143.     short r2;            /* second message row */
  1144.     short c2;            /* second message column */
  1145.     char *m2;            /* second message */
  1146.     short f;            /* prompt flag: 0 = any continue
  1147.                      *        1 = ESC abort
  1148.                      *        2 = any abort */
  1149. #endif
  1150.  
  1151. {
  1152.     char *p;
  1153.  
  1154.     _clearscreen(_GCLEARSCREEN);
  1155.     _settextposition(r1, c1);
  1156.     _outtext(m1);
  1157.     if (m2) {
  1158.         _settextposition(r2, c2);
  1159.         _outtext(m2);
  1160.     }
  1161.     switch (f) {
  1162.     case 0:
  1163.         p = "Press any key to continue.";
  1164.         break;
  1165.     case 1:
  1166.         p = "Press ESC to exit; any other key to continue.";
  1167.         break;
  1168.     default:
  1169.         p = "Press any key to abort.";
  1170.     }
  1171.     PromptMsg(p);
  1172.     return(WaitAnyKey());
  1173. }
  1174.  
  1175.  
  1176. /*
  1177.  * WrDumpF() -- write dump lines to dump file
  1178.  */
  1179.  
  1180. static void
  1181. WrDumpF()
  1182. {
  1183.  
  1184. #if    defined(UNIX)
  1185.     int i;
  1186. #else
  1187.     short i;
  1188. #endif
  1189.  
  1190.     if (Qp) {
  1191.         for (i = 1; i < DumpLc; i++) {
  1192.             if (ParseDumpLn(i, 0) == 0)
  1193.                 break;
  1194.             (void) TrimSpaces(Date);
  1195.             if (Ckdump == 0 && Rtype != RDREG)
  1196.                 continue;
  1197.             (void) TrimSpaces(Time);
  1198.             (void) fprintf(Dumpfs, "%s,%s,%6.2f\n", Date, Time,
  1199.                 Rval);
  1200.         }
  1201.     } else {
  1202.         for (i = 0; i < DumpLc; i++)
  1203.             (void) fprintf(Dumpfs, "%s\n", DumpLp[i]);
  1204.     }
  1205.     (void) fclose(Dumpfs);
  1206.     Dumpfs = NULL;
  1207. }
  1208.