home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1993 #1 / NN_1993_1.iso / spool / comp / sys / hp48 / 6689 < prev    next >
Encoding:
Text File  |  1993-01-05  |  11.0 KB  |  400 lines

  1. Newsgroups: comp.sys.hp48
  2. Path: sparky!uunet!cis.ohio-state.edu!pacific.mps.ohio-state.edu!linac!att!princeton!phoenix.Princeton.EDU!jonhiga
  3. From: jonhiga@phoenix.Princeton.EDU (Jonathan Tomohiko Higa)
  4. Subject: tasc v3beta: ->ASC / ASC->
  5. Message-ID: <1993Jan5.193859.4297@Princeton.EDU>
  6. Originator: news@nimaster
  7. Sender: news@Princeton.EDU (USENET News System)
  8. Nntp-Posting-Host: phoenix.princeton.edu
  9. Organization: Princeton AdTech
  10. Date: Tue, 5 Jan 1993 19:38:59 GMT
  11. Lines: 387
  12.  
  13. BEGIN_DOC README
  14. TASC (version 3-beta) is an ASC <-> HP48 binary translator.
  15.  
  16. Why do you want TASC at all?
  17. 1. Do the translation on another computer instead of on the HP48.  A binary
  18. is approximately half the size of its ASC equivalent; therefore, you
  19. will require less battery power.
  20. 2. It behaves like uuencode to the extent that you don't have to strip off
  21. the non-ASC parts of a post or message if it contains only one ASCed object.
  22. I've been using commands like | "tasc - newgame.bin" within my mail reader
  23. to extract HP48 programs with ease.
  24. 3. There's no memory limit.  Some programs are too large to be
  25. downloaded in ASC form but can still be downloaded in binary form.
  26.  
  27. Why is it better than previous versions?
  28. 1. It determines the file type by inspecting the file instead of expecting
  29. a filename extension.
  30. 2. It determines how to invent a target file name by knowing the source
  31. file's type.
  32. 3. The target file is overwritten when translation begins, not upon
  33. program startup as before.
  34. END_DOC README
  35.  
  36. BEGIN_DOC tasc.1
  37. TASC(1)                  USER COMMANDS                    TASC(1)
  38.  
  39. NAMES
  40.      tasc - translate HP48 binary files to and from ASC format
  41.  
  42. SYNOPSIS
  43.      tasc [opt ...] source [target]
  44.  
  45. DESCRIPTION
  46.      This program translates HP48 binary files to  and  from  ASC
  47.      format.   It  should  be fully compatible with Bill Wickes's
  48.      original ->ASC-> programs.  The symbol "-"  in  place  of  a
  49.      filename  represents  the terminal.  If a target filename is
  50.      not provided, one will be invented by  changing  the  source
  51.      filename's  suffix  to ".asc" or ".bin".  Note that a target
  52.      filename cannot be invented if the  standard  input  is  the
  53.      source.
  54.  
  55. OPTIONS
  56.      -d   Force ASC->bin (ASC decoding) mode.
  57.  
  58.      -e   Force bin->ASC (ASC encoding) mode.
  59.  
  60.      -q   Don't print reports (quiet).
  61.  
  62. DIAGNOSTICS
  63.      Returns 0 on success, 1 on error.   On  successful  exit,  a
  64.      BYTES statement is given if not in quiet mode.
  65.  
  66. AUTHOR
  67.      Jonathan T. Higa (jonhiga@phoenix.princeton.edu)
  68.  
  69. CREDITS
  70.      - ASC:  Bill Wickes (billw@hpcvdw.cv.hp.com).
  71.      - Cyclic Redundancy Check: da Cruz, Frank.  _K_e_r_m_i_t:  _A  _F_i_l_e
  72.      _T_r_a_n_s_f_e_r _P_r_o_t_o_c_o_l. Bedford, MA:  Digital Press, 1987.
  73.      - Object structure: HP48 Tools Manual;  "HP48SX  Internals,"
  74.      by Derek S. Nickel.
  75.      - Guidance:  Joe Horn (akcs.joehorn@hpcvbbs.cv.hp.com)
  76.      - Original inspiration: miscellaneous  asc2bin  programs  on
  77.      seq.uncwil.edu
  78.  
  79. Sun Release 4.1   Last change: 1992 December 26                 1
  80. END_DOC
  81.  
  82. BEGIN_SRC tasc.c
  83. /* tasc (version 3):  ASC-encoder/decoder for HP48 files
  84. Copyright 1992 by Jonathan T. Higa
  85. Credits:
  86. - ASC:  Bill Wickes (billw@hpcvdw.cv.hp.com).
  87. - Cyclic Redundancy Check:
  88. da Cruz, Frank.  _Kermit:  A File Transfer Protocol._
  89. Bedford, MA:  Digital Press, 1987.
  90. - Object structure:
  91. HP48 Tools Manual;
  92. "HP48SX Internals," by Derek S. Nickel.
  93. - Guidance:  Joe Horn (akcs.joehorn@hpcvbbs.cv.hp.com)
  94. - Original inspiration:
  95. miscellaneous asc2bin programs on seq.uncwil.edu
  96. */
  97.  
  98. #include <stdio.h>
  99. #include <string.h>
  100.  
  101. struct hexbuf {
  102.    unsigned long bits;
  103.    long nibs;
  104.    int bsize;
  105.    unsigned short crc;
  106. };
  107.  
  108. enum hpdatatype { HPBIN, HPASC, UNKNOWN = -1 };
  109.  
  110. int verbose = 1;
  111.  
  112. void pushhex(struct hexbuf *b, int h)
  113. /* Add a hex digit to the bit buffer. */
  114. {
  115.    b->bits |= (h & 0xfuL) << b->bsize;
  116.    b->bsize += 4;
  117. }
  118.  
  119. int pophex(struct hexbuf *b)
  120. /* Remove and return a hex digit from the bit buffer, and
  121.    include it in the CRC. */
  122. {
  123.    int h = b->bits & 0xf;
  124.    b->crc = (b->crc >> 4) ^ (((b->crc ^ h) & 0xf) * 0x1081);
  125.    b->nibs++;
  126.    b->bits >>= 4;
  127.    b->bsize -= 4;
  128.    return h;
  129. }
  130.  
  131. enum hpdatatype hptype(FILE *f)
  132. /* Determine the type of HP file by scanning the beginning of the file.
  133.    If the type is known, put the file pointer at the start of data. */
  134. {
  135.    char c;
  136.    if (fscanf(f, "HPHP48-%c", &c) == 1)
  137.       return HPBIN;
  138.    else
  139.       for (; ; )
  140.      switch (fscanf(f, "%*[%]HP:%*[^;]%c", &c)) {
  141.      case 1:
  142.         while (fscanf(f, " @%c", &c) == 1) {
  143.            if (c != '\n') {
  144.           fscanf(f, "%*[^\n]");
  145.           fscanf(f, "%*1[\n]");
  146.            }
  147.         }
  148.         return fscanf(f, "%c", &c) == 1 && c == '"' ? HPASC : UNKNOWN;
  149.      case 0:
  150.         fscanf(f, "%*[^\n]");
  151.         fscanf(f, "%*1[\n]");
  152.         break;
  153.      case EOF:
  154.         return UNKNOWN;
  155.      }
  156. }
  157.  
  158. char *newext(char *new, const char *old, const char *ext)
  159. /* Create a new filename from the old filename and extension. */
  160. {
  161.    char *p = strrchr(strcpy(new, old), ext[0]);
  162.    if (p) strcpy(p, ext);
  163.    else strcat(new, ext);
  164.    if (verbose) fprintf(stderr, "tasc: inventing filename \"%s\"\n", new);
  165.    return new;
  166. }
  167.  
  168. int asctobin(FILE *fasc, FILE *fbin)
  169. {
  170.    struct hexbuf hb = {0, 0, 0, 0};
  171.    int d;
  172.  
  173.    /* write header into binary file */
  174.    fputs("HPHP48-E", fbin);
  175.  
  176.    /* translate data */
  177.    while (fscanf(fasc, "%1x", &d) == 1) {
  178.       pushhex(&hb, d);
  179.       if (hb.bsize >= 24) {
  180.      d = pophex(&hb);
  181.      d |= pophex(&hb) << 4;
  182.      putc(d, fbin);
  183.       }
  184.    }
  185.    if (hb.bsize > 16) {
  186.       d = pophex(&hb);
  187.       putc(d, fbin);
  188.    }
  189.  
  190.    /* check CRC */
  191.    if (hb.crc != hb.bits || hb.bsize != 16) {
  192.       fprintf(stderr, "tasc: ASC->bin: CRC is incorrect\n");
  193.       return 1;
  194.    }
  195.    if (verbose)
  196.       fprintf(stderr, "tasc: ASC->bin: BYTES: #%hXh %ld%s\n",
  197.               hb.crc, hb.nibs/2, hb.nibs & 1 ? ".5" : "");
  198.    return 0;
  199. }
  200.  
  201. int bintoasc(FILE *fbin, FILE *fasc)
  202. {
  203.    struct hexbuf hb = {0, 0, 0, 0};
  204.    unsigned long fldlen = 0;
  205.    enum { SIZE, ASCIC, ASCIX, DIR, ANY = -1 } fldnxt = ANY;
  206.    int c, width = 0;
  207.  
  208.    /* write header into ASC file */
  209.    fprintf(fasc, "%%%%HP: T(1);\n\"");
  210.  
  211.    /* parse binary */
  212.    while ((c = getc(fbin)) != EOF) {
  213.       pushhex(&hb, c);
  214.       pushhex(&hb, c >> 4);
  215.       if (!fldlen) /* done with previous field */
  216.      switch (fldnxt) { /* now for the current field */
  217.      case SIZE:
  218.         if (hb.bsize >= 20) {
  219.            /* this object's length is known by the size field */
  220.            fldlen = hb.bits & 0xfffff;
  221.            fldnxt = ANY;
  222.         }
  223.         break;
  224.      case ASCIC:
  225.         if (hb.bsize >= 8) {
  226.            /* ASCII-char identifier */
  227.            fldlen = 2 + 2 * (hb.bits & 0xff);
  228.            fldnxt = ANY;
  229.         }
  230.         break;
  231.      case ASCIX:
  232.         if (hb.bsize >= 8) {
  233.            /* ASCII-extended identifier */
  234.            fldlen = 4 + 2 * (hb.bits & 0xff);
  235.            fldnxt = ANY;
  236.         }
  237.         break;
  238.      case DIR:
  239.         if (hb.bsize >= 20) {
  240.            /* first object pointer in a directory, to an ASCIX name */
  241.            fldlen = hb.bits & 0xfffff;
  242.            fldnxt = ASCIX;
  243.         }
  244.         break;
  245.      default:
  246.         if (hb.bsize >= 20) {
  247.            unsigned long pro = hb.bits & 0xfffff;
  248.            fldlen = 5; /* the prolog field is 5 nibbles long */
  249.            if (pro == 0x29e8uL || pro == 0x2a0auL || pro == 0x2a2cuL
  250.            || pro == 0x2a4euL || pro == 0x2b1euL || pro == 0x2b40uL
  251.            || pro == 0x2b62uL || pro == 0x2b88uL || pro == 0x2dccuL)
  252.           fldnxt = SIZE; /* expect a size field */
  253.            else if (pro == 0x2e48uL || pro == 0x2e6duL || pro == 0x2afcuL)
  254.           fldnxt = ASCIC; /* expect an ASCIC object */
  255.            else if (pro == 0x2a96uL) {
  256.           /* expect the directory pointer after the first 8 nibbles */
  257.           fldlen = 8;
  258.           fldnxt = DIR;
  259.            }
  260.            else if (pro == 0x2911uL) fldlen = 10; /* is system binary */
  261.            else if (pro == 0x2933uL) fldlen = 21; /* is real */
  262.            else if (pro == 0x2955uL) fldlen = 26; /* is long real */
  263.            else if (pro == 0x2977uL) fldlen = 37; /* is complex */
  264.            else if (pro == 0x299duL) fldlen = 47; /* is long complex */
  265.            else if (pro == 0x29bfuL) fldlen = 7; /* is char */
  266.            else if (pro == 0x2e92uL) fldlen = 11; /* is XLIB name */
  267.         }
  268.         break;
  269.      }
  270.       
  271.       /* write out the current field */
  272.       while (fldlen && hb.bsize) {
  273.      c = pophex(&hb);
  274.      if (width == 64) {
  275.         putc('\n', fasc);
  276.         width = 0;
  277.      }
  278.      fprintf(fasc, "%X", c);
  279.      width++;
  280.      fldlen--;
  281.       }
  282.    }
  283.    if (hb.bits) {
  284.       fprintf(stderr, "tasc: bin->ASC: end of last object not found\n");
  285.       return 1;
  286.    }
  287.  
  288.    /* append CRC */
  289.    if (verbose)
  290.       fprintf(stderr, "tasc: bin->ASC: BYTES: #%hXh %ld%s\n",
  291.               hb.crc, hb.nibs / 2, hb.nibs & 1 ? ".5" : "");
  292.    hb.bits = hb.crc;
  293.    hb.bsize = 16;
  294.    while (hb.bsize) {
  295.       if (width == 64) {
  296.      putc('\n', fasc);
  297.      width = 0;
  298.       }
  299.       fprintf(fasc, "%X", pophex(&hb));
  300.       width++;
  301.    }
  302.    fprintf(fasc, "\"\n");
  303.    return 0;
  304. }
  305.  
  306. int main(int argc, char **argv)
  307. {
  308.    const char *STDIO = "-";
  309.    enum hpdatatype coding = UNKNOWN;
  310.    int i = 1;
  311.    char *iname, *oname, temp[256];
  312.    if (argc > i && argv[i][0] == '-') {
  313.       switch (argv[i][1]) {
  314.       case 'd':
  315.      coding = HPASC;
  316.      i++;
  317.      break;
  318.       case 'e':
  319.      coding = HPBIN;
  320.      i++;
  321.      break;
  322.       case 'q':
  323.          verbose = 0;
  324.          i++;
  325.          break;
  326.       }
  327.    }
  328.    argc -= i;
  329.    if (argc < 1 || argc > 2) {
  330.       fprintf(stderr, "Use: %s [opt ...] source [target]\n"
  331.               "opt\taction\n"
  332.               " -d\tForce ASC->bin (ASC decode)\n"
  333.               " -e\tForce bin->ASC (ASC encode)\n"
  334.               " -q\tSuppress non-error messages (quiet)\n"
  335.               "The filename \"-\" represents the terminal.\n",
  336.               argv[0]);
  337.       return 1;
  338.    }
  339.    iname = argv[i];
  340.    if (strcmp(iname, STDIO)) {
  341.       if (!freopen(iname, "rb", stdin)) {
  342.      fprintf(stderr, "tasc: ");
  343.      perror(iname);
  344.      return 1;
  345.       }
  346.    } else if (argc == 1) {
  347.       fprintf(stderr, "tasc: cannot invent output filename for stdin\n");
  348.       return 1;
  349.    }
  350.    switch (hptype(stdin)) {
  351.    case HPASC:
  352.       if (coding == HPBIN) {
  353.      fprintf(stderr, "tasc: ASC->bin mode was disallowed\n");
  354.      return 1;
  355.       }
  356.       if (verbose) fprintf(stderr, "tasc: entering ASC->bin mode\n");
  357.       oname = argc == 1 ? newext(temp, iname, ".bin") : argv[i+1];
  358.       if (strcmp(oname, STDIO) && !freopen(oname, "wb", stdout)) {
  359.      fprintf(stderr, "tasc: ");
  360.      perror(oname);
  361.      return 1;
  362.       }
  363.       if (asctobin(stdin, stdout))
  364.      return 1;
  365.       break;
  366.    case HPBIN:
  367.       if (coding == HPASC) {
  368.      fprintf(stderr, "tasc: bin->ASC mode was disallowed\n");
  369.      return 1;
  370.       }
  371.       if (verbose) fprintf(stderr, "tasc: entering bin->ASC mode\n");
  372.       oname = argc == 1 ? newext(temp, iname, ".asc") : argv[i+1];
  373.       if (strcmp(oname, STDIO) && !freopen(oname, "w", stdout)) {
  374.      fprintf(stderr, "tasc: ");
  375.      perror(oname);
  376.      return 1;
  377.       }
  378.       if (bintoasc(stdin, stdout))
  379.      return 1;
  380.       break;
  381.    default:
  382.       fprintf(stderr, "tasc: unknown input type\n");
  383.       return 1;
  384.    }
  385.    if (fclose(stdin)) {
  386.       fprintf(stderr, "tasc: ");
  387.       perror(iname);
  388.       return 1;
  389.    }
  390.    if (fclose(stdout)) {
  391.       fprintf(stderr, "tasc: ");
  392.       perror(oname);
  393.       return 1;
  394.    }
  395.    return 0;
  396. }
  397. END_SRC
  398. -- 
  399. Jon (jonhiga@phoenix.princeton.edu)
  400.