home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / CONTRIB / MBASE / MBASE51.TAR / mbase51 / src / mbconv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-04  |  7.9 KB  |  348 lines

  1. /*
  2.  * METALBASE 5.1
  3.  *
  4.  * Released January 1st, 1993 by Huan-Ti [ t-richj@microsoft.com ]
  5.  *
  6.  */
  7.  
  8. #include <mbase.h>
  9. #include "internal.h"  /* Because we do some non-standard record moving */
  10.  
  11.  
  12. /*
  13.  * PROTOTYPES -----------------------------------------------------------------
  14.  *
  15.  */
  16.  
  17.    void   main         XARGS( (int,        char **) );
  18.    mb_err convert      XARGS( (relation *, relation *) );
  19.    void   finalize     XARGS( (char *,     char *) );
  20.  
  21. #ifndef MSDOS
  22.    int    rename       XARGS( (char *,     char *) );
  23. #endif
  24.  
  25.  
  26. /*
  27.  * ROUTINES -------------------------------------------------------------------
  28.  *
  29.  */
  30.  
  31. relation *rel;
  32. relation *new;
  33.  
  34. char    tempname[128];
  35.  
  36. void
  37. main  (argc, argv)
  38. int    argc;
  39. char **argv;
  40. {
  41.    char *str;
  42.    bool  fDone = FALSE;
  43.  
  44.    for (--argc,++argv; argc; --argc,++argv)
  45.       {
  46.       if (*(str = *argv) == '-')
  47.          {
  48.          fprintf (stderr, "option %s unrecognized.\n", 1+str);
  49.          continue;
  50.          }
  51.  
  52.       fDone = TRUE;
  53.  
  54.       if ((rel = mb_old (str, 0)) == RNULL)
  55.          {
  56.          fprintf (stderr, "%s: %s.\n", str, mb_error);
  57.          continue;
  58.          }
  59.  
  60.       if (rel->ver >= verLOWEST)
  61.          {
  62.          fprintf (stderr, "%s is in a compatible format.\n", str);
  63.          MB_RemoveRelation (rel);
  64.          continue;
  65.          }
  66.  
  67.       if ((new = mb_new ()) == RNULL)
  68.          {
  69.          fprintf (stderr, "%s.\n", mb_error);
  70.          mb_die();
  71.          continue;
  72.          }
  73.  
  74.       strcpy (tempname, str);
  75.       if (! strncmp (&tempname[strlen(tempname)-4], ".rel", 4))
  76.          {
  77.          tempname[strlen(tempname)-4] = 0;
  78.          }
  79.       strcat (tempname, ".tmp");
  80.  
  81.       if (convert (new, rel) == MB_OKAY)
  82.          {
  83.          MB_RemoveRelation (rel);
  84.          finalize (tempname, str);  /* Removes original and renames new */
  85.          }
  86.       else
  87.          {
  88.          MB_RemoveRelation (rel);
  89.          fprintf (stderr, "%s.\n", mb_error);
  90.          }
  91.  
  92.       mb_rmv (new);  /* Free any memory used by mb_new() */
  93.       }
  94.  
  95.    if (! fDone)
  96.       {
  97.       fprintf (stderr, "format: mbconv oldrelation [oldrelation...]\n");
  98.       mb_exit (1);
  99.       }
  100.  
  101.    mb_exit (0);
  102. }
  103.  
  104. mb_err
  105. convert  (new,  rel)
  106. relation *new, *rel;
  107. {
  108.    long    nexts, numrec, arg;
  109.    char    desc[128], t2[5];
  110.    char   *ptr;
  111.    int     i, j, len;
  112.  
  113. /*
  114.  * The format for the relation header is something like this:
  115.  *
  116.  *    offset for      offset for
  117.  *   pre-4.1 ver     post-4.0 ver    field
  118.  *  -------------   --------------   --------------------------------
  119.  *       0                0          1-char: signature for MB version
  120.  *               ...
  121.  *       2                6          4-char: pointer to fields
  122.  *       6               10          4-char: pointer to indices
  123.  *      10               14          4-char: pointer to record zero
  124.  *      14 (POS_NUMREC)  18          4-char: number of records
  125.  *      18               22          4-char: next serial value
  126.  *      22               26          2-char: number of fields
  127.  *      24               28          2-char: number of indices
  128.  *      26 (POS_INDICES) 30          4*nIdx: top-of-index array
  129.  *
  130.  */
  131.  
  132.    if (rel->ver == verMINIMUM)
  133.       lseek (rel->fhRel, POS_OLDNUMREC, 0);
  134.    else
  135.       lseek (rel->fhRel, POS_NUMREC, 0);
  136.  
  137.    readx (rel->fhRel, &numrec, 4);
  138.    readx (rel->fhRel, &nexts,  4);
  139.  
  140. /*
  141.  * First, the fields...
  142.  *
  143.  */
  144.  
  145.    for (i = 0; i < rel->nFld; i++)
  146.       {
  147.       switch (rel->fldType[i])
  148.          {
  149.          case T_SERIAL:  arg = nexts;          break;
  150.          case T_CHAR:    arg = rel->cbLen[i];  break;
  151.          case T_BYTE:    arg = rel->cbLen[i];  break;
  152.          default:        arg = 0L;             break;
  153.          }
  154.  
  155.       if (mb_addfield (new, rel->fldName[i], rel->fldType[i], arg) != MB_OKAY)
  156.          {
  157.          Error (mb_errno);
  158.          }
  159.       }
  160.  
  161. /*
  162.  * Next, the indices...
  163.  *
  164.  */
  165.  
  166.    for (i = 0; i < rel->nIdx; i++)
  167.       {
  168.       desc[0] = 0;
  169.  
  170.       for (j = 0; j < rel->nIdxFld[i]; j++)
  171.          {
  172.          sprintf (t2, "%d", rel->idxFld[i][j]);
  173.  
  174.          if (j != 0)
  175.             strcat (desc, ",");
  176.          strcat (desc, t2);
  177.          }
  178.  
  179.       if (mb_addindex (new, rel->idxName[i], rel->fDups[i], desc) != MB_OKAY)
  180.          {
  181.          Error (mb_errno);
  182.          }
  183.       }
  184.  
  185. /*
  186.  * Now create it, and open the resulting file...
  187.  *
  188.  */
  189.  
  190.    if (mb_create (new, tempname, 0) != MB_OKAY)
  191.       {
  192.       Error_2 (mb_errno);
  193.       }
  194.  
  195.    if ((new->fhRel = openx (tempname, OPENMODE)) <= 0)
  196.       {
  197.       Error_2 (MB_NO_READ);
  198.       }
  199.  
  200. /*
  201.  * The number of records is reset to zero inside the new relation, so since
  202.  * we read it from the rel relation earlier, write it out where it needs to
  203.  * be (see why I had to include internal.h?).  Oh, and grab a buffer big
  204.  * enough to move an entire record, with indices intact...
  205.  *
  206.  */
  207.  
  208.    lseek (new->fhRel, POS_NUMREC, 0);
  209.    writx (new->fhRel, &numrec, 4);
  210.  
  211.    len = (int)(rel->cbRecord + cbINDEX * rel->nIdx);
  212.  
  213.    if ((ptr = (char *)malloc (len +1)) == NULL)
  214.       {
  215.       Error_3 (MB_NO_MEMORY);
  216.       }
  217.  
  218. /*
  219.  * Great.  Problem is, the new header is bigger than older versions... so
  220.  * read each record, and write it out at the new place in the new relation.
  221.  * Record numbers are offsets relative to ->recz, so they won't have to change
  222.  * this way.
  223.  *
  224.  * We also have to initialize the top-of-index pointers, which aren't set
  225.  * by mb_create() (obviously).
  226.  *
  227.  */
  228.  
  229.    if (rel->ver == verMINIMUM)
  230.       lseek (rel->fhRel, POS_OLDINDICES, 0);
  231.    else
  232.       lseek (rel->fhRel, POS_INDICES, 0);
  233.  
  234.    lseek (new->fhRel, POS_INDICES,    0);
  235.  
  236.    for (i = 0; i < rel->nIdx; i++)
  237.       {
  238.       readx (rel->fhRel, &arg, 4);
  239.       writx (new->fhRel, &arg, 4);
  240.       }
  241.  
  242.  
  243.    lseek (rel->fhRel, rel->posRecZ, 0); /* posRecZ was set by mb_old()    */
  244.    lseek (new->fhRel, new->posRecZ, 0); /* posRecZ was set by mb_create() */
  245.  
  246.    for (arg = 0L; arg < numrec; arg++)  /* arg == which record we're moving */
  247.       {
  248.       if ((readx (rel->fhRel, ptr, len)) != len)
  249.          {
  250.          free (ptr);
  251.          Error_3 (MB_CORRUPT);
  252.          }
  253.       if ((writx (new->fhRel, ptr, len)) != len)
  254.          {
  255.          free (ptr);
  256.          Error_3 (MB_DISKFULL);
  257.          }
  258.       }
  259.  
  260.    free (ptr);
  261.    SetError (MB_OKAY);
  262.  
  263. lblERROR_3:
  264.    close (new->fhRel);
  265.  
  266. lblERROR_2:
  267.    if (mb_errno != MB_OKAY)
  268.       {
  269.       unlink (tempname);
  270.       }
  271.  
  272. lblERROR:
  273.    return mb_errno;
  274. }
  275.  
  276. #ifndef MSDOS
  277. int
  278. rename (new, rel)
  279. char   *new,*rel;
  280. {
  281.    if (link (rel, new) != 0)  return -1;
  282.    if (unlink (rel) != 0)     return -2;
  283.    return 0;
  284. }
  285. #endif
  286.  
  287. void
  288. finalize (newname, oldname)
  289. char     *newname,*oldname;
  290. {
  291.    long  sizea, sizeb;
  292.    int   fh;
  293.  
  294. /*
  295.  * If we got here, convert() already closed all file pointers, so we can
  296.  * do this safely.  First come the sanity checks--make sure we can open
  297.  * and read/write both files, and make sure the new file is larger than
  298.  * the original (if it isn't, we didn't finish converting, regardless of
  299.  * what convert() said).
  300.  *
  301.  */
  302.  
  303.    if (strncmp (&oldname[strlen(oldname)-4], ".rel", 4))
  304.       {
  305.       strcat (oldname, ".rel");
  306.       }
  307.  
  308.    if ((fh = openx (oldname, OPENMODE)) < 0)
  309.       {
  310.       fprintf (stderr, "mb_conv: could not open %s.\n", oldname);
  311.       return;
  312.       }
  313.    sizea = lseek (fh, 0L, 2);  /* Find the filesize */
  314.    close (fh);
  315.  
  316.    if ((fh = openx (newname, OPENMODE)) < 0)
  317.       {
  318.       fprintf (stderr, "mb_conv: could not open %s.\n", newname);
  319.       return;
  320.       }
  321.    sizeb = lseek (fh, 0L, 2);  /* Find the filesize */
  322.    close (fh);
  323.  
  324.    if (sizea > sizeb)
  325.       {
  326.       fprintf (stderr, "mb_conv: could not finish conversion!\n");
  327.       return;
  328.       }
  329.  
  330. /*
  331.  * Fine--looks like we converted it just dandy.  So delete the original
  332.  * file, and rename our temporary one so it looks like the old one.  Note that
  333.  * rename() for DOS doesn't exist with almost any *nix compiler, so I use my
  334.  * own if MSDOS isn't defined.
  335.  *
  336.  */
  337.  
  338.    printf ("mb_conv: %s converted successfully.\n", oldname);
  339.  
  340.    unlink (oldname);
  341.    if (rename (newname, oldname) != 0)
  342.       {
  343.       fprintf (stderr, "But, the rename didn't work.\n");
  344.       fprintf (stderr, "Rename %s to %s yourself.\n", newname, oldname);
  345.       }
  346. }
  347.  
  348.