home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / dtx9303 / ms_c_7 / vcopy / vcopy.c next >
Encoding:
C/C++ Source or Header  |  1993-05-17  |  16.8 KB  |  413 lines

  1. /*=======================================================*/
  2. /*                        VCOPY.C                        */
  3. /*     Copyright (C) 1993 Thomas Wölker und DMV-Verlag   */
  4. /*-------------------------------------------------------*/
  5. /* Compiler: Microsoft C/C++ 7.0                         */
  6. /* Funktion: Beispiel für die Verwendung des virtuellen  */
  7. /*           Memory Managers unter MSC 7.00 / DOS        */
  8. /*           Das Programm kopiert unter Verwendung des   */
  9. /*           VMM Dateien an einem Stück. Zu diesem Zweck */
  10. /*           wird eine verkettete Liste von 32 KByte     */
  11. /*           großen Blöcken aus virtuellen Speicherhand- */
  12. /*           les erzeugt. Die gesamte Sourcedatei wird   */
  13. /*           zunächst gelesen (in den virtuellen Heap)   */
  14. /*           und dann aus dem virtuellen Heap wieder     */
  15. /*           geschrieben. Dies ist zwar nicht gerade eine*/
  16. /*           tolle Anwendung (vor allem, wenn man nur    */
  17. /*           sehr wenig XMS/EMS hat) demonstriert aber   */
  18. /*           die Handhabung der _vmemory-Funktionen doch */
  19. /*           ganz gut.                                   */
  20. /*=======================================================*/
  21.  
  22. #include <vmemory.h>
  23. #include <stdlib.h>
  24. #include <stdio.h>
  25. #include <fcntl.h>
  26. #include <io.h>
  27. #include <sys\types.h>
  28. #include <sys\stat.h>
  29. #include <dos.h>
  30. #include <bios.h>
  31. #include <malloc.h>
  32. #include <conio.h>
  33. #include "vcopy.h"
  34.  
  35. /*-------------------------------------------------------*/
  36. /* Name:     main                                        */
  37. /* Funktion: Eintrittspunkt                              */
  38. /*           Der 1. Parameter ist die zu kopierende Da-  */
  39. /*           tei, der 2. der Name der Zieldatei.         */
  40. /* Achtung:  Eine bereits vorhandene Datei wird über-    */
  41. /*           schrieben). Gibt es einen dritten Parm, so  */
  42. /*           werden noch Debuginformationen              */
  43. /*           ausgegeben.                                 */
  44. /*-------------------------------------------------------*/
  45. BOOL isDebug = FALSE;
  46.  
  47. #define Use "Usage: vcopy src dest [debug]"
  48.  
  49. void main(
  50.           int argc,                     // Argument-Counter
  51.           char * argv[])                // Argumentvektor
  52. {
  53.    WORD nRet;
  54.    if (argc == 4) isDebug = TRUE;
  55.    if (argc < 3) exit(printf("\n%s", Use));
  56.    nRet = Copy(argv[1], argv[2]);
  57.     /*--------------------------------------------*/
  58.     /* an dieser Stelle sollte man den Returnwert */
  59.     /* komplett abtesten und auswerten            */                  */
  60.     /*--------------------------------------------*/
  61.    if (nRet != CP_OK) printf("\nFehler in copy()");
  62.    exit(0);
  63. }
  64.  
  65. /*-------------------------------------------------------*/
  66. /* Name:     Copy                                        */
  67. /* Funktion: Kopiert File Src nach Dest                  */
  68. /*-------------------------------------------------------*/
  69. WORD Copy(
  70.           char * pszSrc,          // Quelle
  71.           char * pszDest )        // Ziel
  72. {
  73.   int      hSrc, hDest;           // Quell- und Zieldatei
  74.   long     cSrcSize,              // Größe der Source
  75.            cToRead,               // Noch zu lesende Bytes
  76.            cRead;                 // Bereits gelesene Bytes
  77.   int      nReturn;               // Return von VLRead
  78.   VMROOT   vmRoot;                // Root der VL des VMM
  79.   size_t   cWritten;              // Geschriebene Bytes
  80.   unsigned iBlocks;               // Index in Blöcken
  81.  
  82.   hSrc=_open(                     // Sourcefile öffnen
  83.              pszSrc,              // Name des Files
  84.              _O_RDONLY|_O_BINARY  // Open Mode
  85.             );
  86.  
  87.   if (hSrc == -1)                 // Fehler beim Öffnen?
  88.       return CP_ERROPENSOURCE;    // zurück
  89.    hDest = _open(                 // Ziel öffnen
  90.                  pszDest,         // Name des Ziels
  91.                  _O_WRONLY |
  92.                  _O_BINARY |
  93.                  _O_CREAT  |
  94.                  _O_TRUNC,
  95.                  _S_IREAD  |
  96.                  _S_IWRITE);      // Modus
  97.    if (hDest == -1)               // Fehler beim Öffnen
  98.    {
  99.       _close(hSrc);               // Source schließen
  100.       return CP_ERROPENDEST;      // Fehler zurück
  101.    }
  102.    cSrcSize=_filelength(hSrc);    // Größe der Quelldatei
  103.                                   // Erste zu lesende
  104.                                   //   Blockgröße bestimmen
  105.    if (cSrcSize <= CP_BLOCKSIZE)  // Datei paßt komplett
  106.     {                             //   in Block
  107.       cToRead = cSrcSize;
  108.    }
  109.    else                           // Datei braucht mehrere
  110.    {                              //   Blöcke
  111.       cToRead = CP_BLOCKSIZE;
  112.    }
  113.    cRead = 0L;                 // Anzahl bisher gelesen = 0
  114.    do                          // Ersten Block lesen
  115.    {
  116.       if ((nReturn = VLRead(hSrc, cToRead, &vmRoot))
  117.            != CP_OK)
  118.       {                  // Hier ist ein Fehler aufgetreten
  119.          _close( hSrc );         // Source schließen
  120.          _close( hDest );        // Ziel schließen
  121.          VLPanicAbort( vmRoot ); // PANIK !
  122.          return nReturn;         // Fehler zurück
  123.       }
  124.       cRead += cToRead;          // Gelesene Bytes erhöhen
  125.                            // Nächste Blockgröße festlegen
  126.       if ((cRead + cToRead) > cSrcSize)
  127.          cToRead = cSrcSize - cRead;
  128.    } while (cToRead != 0);
  129.                                  // Dest schreiben
  130.    vmRoot.pAct = vmRoot.pFirst;
  131.                                  // Alle Blöcke schreiben
  132.    for (iBlocks = 0;
  133.         iBlocks < vmRoot.cBlocks;
  134.         iBlocks++)
  135.    {
  136.       int __far *pMem;
  137.                                 // Speicherblock verriegeln
  138.       if ((pMem = (int __far*)_vlock(vmRoot.pAct -> hVM))
  139.          == NULL)
  140.       {
  141.          VLPanicAbort(vmRoot);
  142.          return CP_ERRLOCK;
  143.       }
  144.  
  145.       cWritten = _write(            // Block schreiben
  146.                  hDest,
  147.                  pMem,
  148.                  (unsigned)
  149.                  (vmRoot.pAct -> cSize));
  150.                // Hier wird getestet, ob geschriebene Größe
  151.                // ungleich der gewollten Größe ist
  152.       if (cWritten != (size_t) (vmRoot.pAct -> cSize))
  153.       {
  154.          VLPanicAbort(vmRoot);
  155.          return CP_ERRWRITE;
  156.       }
  157.                                  // Block wieder entriegeln
  158.       _vunlock(vmRoot.pAct -> hVM, _VM_CLEAN);
  159.                                  // Nächster Block
  160.       vmRoot.pAct = vmRoot.pAct -> pNext;
  161.    }
  162.    _close(hSrc);                 // Source schließen
  163.    _close(hDest);                // Ziel schließen
  164.    // Liste deinitialisieren
  165.    if (! VLDeinit( vmRoot)) return CP_ERRVLDEINIT;
  166.    return CP_OK;                 // OK zurück
  167. }
  168.  
  169. /*-------------------------------------------------------*/
  170. /* Name:     VLRead                                      */
  171. /* Funktion: Liest einen Block aus der Quelldatei in     */
  172. /*           einen Speicherbereich des virtuellen        */
  173. /*           Speichermanagers                            */
  174. /*-------------------------------------------------------*/
  175. WORD VLRead(
  176.             int    hFile,               // Filehandle
  177.             long   cBlockSize,          // Blockgröße
  178.             VMROOT * vmr)               // VL-VMM Rootptr
  179. {
  180.    VMNODE * pvmNode;            // Zeiger auf einen Knoten
  181.    static BOOL isFirst = TRUE;  // Flag, ob Erster Knoten
  182.    if (isFirst)                 // Wenn erster ...
  183.    {
  184.       if (! VLInit(vmr))        // Liste init
  185.       {
  186.          return CP_ERRVLINIT;   // Falls Fehler... zurück
  187.       }
  188.       isFirst = FALSE;          // Flag zurück
  189.    }
  190.                                 // weiteren Block anfordern
  191.    pvmNode = VLAddBlock(vmr, cBlockSize);
  192.    if (pvmNode == (VMNODE*)NULL) return CP_ERRVMALLOC;
  193.                                 // Block einlesen
  194.    if (VLReadBlock(
  195.                    pvmNode,
  196.                    hFile,
  197.                    cBlockSize) != CP_OK)
  198.       return CP_ERRVLREAD;
  199.    return CP_OK;
  200. }
  201.  
  202. /*-------------------------------------------------------*/
  203. /* Name:     VLInit                                      */
  204. /* Funktion: Initialisiert die verkettete Liste aus      */
  205. /*           VMSpeicherblöcken. Dabei tritt ein          */
  206. /*           interessantes Problem auf: Microsoft sagt   */
  207. /*           in der »Runtime Lib Reference«, daß die     */
  208. /*           ersten beiden Paramter von _vheapinit       */
  209. /*           Größen in Paragraphen angeben, sagen aber   */
  210. /*           netterweise nicht, wie groß so ein Para-    */
  211. /*           graph wohl sein mag.                        */
  212. /*           Wird für DOSMAX _VM_ALLDOS verwendet, hat   */
  213. /*           man das Problem, daß vom Heap praktisch     */
  214. /*           nichts mehr überbliebt. Auf diese Weise     */
  215. /*           versagt das malloc für die einzelnen Nodes  */
  216. /*           extrem schnell, da der MemMgr den gesamten  */
  217. /*           Heap für sich beansprucht.                  */
  218. /*           Mit den hier verwendeten Parametern stehen  */
  219. /*           nach dem Init noch etwa 30 K für malloc zur */
  220. /*           Verfügung. Dies führt zu der Rechnung, daß  */
  221. /*           bei etwa 630 K freiem Speicher (DOS 5,      */
  222. /*           386Max) 30-KByte-Exefile (mit CV info) ein  */
  223. /*           Paragraph wohl ca. 18 Byte groß sein muß... */
  224. /*-------------------------------------------------------*/
  225. BOOL VLInit(VMROOT *pRoot )                  // RootZeiger
  226. {
  227.                             // Alles fürs swappen benutzen
  228.    if (_vheapinit(
  229.            2048,            // 32 KBytes in Paragraphen
  230.            32000,           // 512 KBytes in Paragraphen
  231.            _VM_ALLSWAP) == 0)
  232.    {
  233.       return FALSE;
  234.    }
  235.                             // Liste initialisieren
  236.    pRoot -> cBlocks = 0;
  237.    pRoot -> pFirst  = (VMNODE*)NULL;
  238.    pRoot -> pAct    = (VMNODE*)NULL;
  239.    return TRUE;
  240. }
  241.  
  242. /*-------------------------------------------------------*/
  243. /* Name:     VLAddBlock                                  */
  244. /* Funktion: Versucht zunächst eine neue Node auf dem    */
  245. /*           Heap zu allozieren.Wenn dies gelingt, wird  */
  246. /*           in dieser Node ein Speicherblock über den   */
  247. /*           VM angefordert. Gelingt dies, wird die Node */
  248. /*           in die Liste eingefügt.                     */
  249. /*-------------------------------------------------------*/
  250. VMNODE * VLAddBlock(
  251.                     VMROOT *pRoot,          // Root-Zeiger
  252.                     long   cSize )          // Blockgröße
  253. {
  254.                                            // letzer Knoten
  255.    static VMNODE * pLast = (VMNODE*)NULL;
  256.                         // Speicher für einen Knoten holen
  257.    pRoot -> pAct = (VMNODE*)malloc(sizeof(VMNODE));
  258.                         // Speicherstatistik anzeigen
  259.    MemoryStatistics();  // Testen, ob Speicher vorhanden
  260.    if (pRoot -> pAct == (VMNODE*)NULL)
  261.    {
  262.    return (VMNODE*)NULL;                   // Fehler zurück
  263.    }
  264.                       // Versuchen, einen Speicherblock der
  265.                       // benötigten Größe zu bekommen
  266.    if ((pRoot -> pAct -> hVM = _vmalloc(
  267.                                cSize)) == _VM_NULL)
  268.    {
  269.                // Wenns nicht ging, auch die Node freigeben
  270.       free(pRoot -> pAct);
  271.       return (VMNODE*)NULL;      // Und Fehler zuück
  272.    }
  273.    pRoot -> cBlocks++;           // Blockzahl erhöhen
  274.    pRoot -> pAct -> cSize=cSize; // Größe des Blocks merken
  275.                 // Informationen über diesen Block anzeigen
  276.    BlockStatistics(pRoot -> pAct, pRoot -> cBlocks);
  277.                            // Wenn dies die 1. Node ist ...
  278.    if (pRoot -> cBlocks == 1)
  279.    {
  280.       pRoot -> pFirst = pRoot -> pAct; // ... pFirst merken
  281.    }
  282.    else                                // ... sonst ...
  283.    {                          // ... Node in Liste einfügen
  284.       pLast -> pNext = pRoot -> pAct;
  285.    }
  286.    pLast = pRoot -> pAct;     // aktuelle merken
  287.    return pLast;              // und zurück damit
  288. }
  289.  
  290. /*-------------------------------------------------------*/
  291. /* Name:     VLReadBlock                                 */
  292. /* Funktion: Liest einen Block aus der Datei in einen    */
  293. /*           Block des VMM                               */
  294. /*-------------------------------------------------------*/
  295. WORD VLReadBlock(
  296.                  VMNODE *pNode,             // Knotenzeiger
  297.                  int hFile,                 // Filehandle
  298.                  long cSize )               // Blockgröße
  299. {
  300.                   // Pointer to VM-Block in FAR Dos Memory
  301.    int __far *pMem;
  302.                                // Lock the block
  303.    if((pMem = (int __far *)_vlock(pNode -> hVM)) == NULL)
  304.    {
  305.       return CP_ERRLOCK;       // Return attempt failure
  306.    }
  307.                                // Versuch, Datei einzulesen
  308.    if ( _read(                 // Lesen
  309.            hFile,              // da raus
  310.            pMem,               // da rein
  311.            (unsigned)cSize     // soviel
  312.            ) == -1)
  313.            return CP_ERRVLREAD;        // Fehler
  314.    _vunlock( pNode->hVM, _VM_DIRTY );  // Unlock the Block
  315.    return CP_OK;                       // OK zurück
  316. }
  317.  
  318. /*-------------------------------------------------------*/
  319. /* Name:     VLDeinit                                    */
  320. /* Funktion: Deinitialisiert die Liste aus VM-Blöcken.   */
  321. /*           Dazu wird einfach jede einzelne Node an-    */
  322. /*           gelaufen, deren VM Handle freigegeben und   */
  323. /*           dann die Node dem Heap der Laufzeit zurück- */
  324. /*           gegeben.                                    */
  325. /*-------------------------------------------------------*/
  326. BOOL VLDeinit(VMROOT vmRoot)                 // Root Object
  327. {
  328.    VMNODE * pNext;                    // Nächstes Element
  329.    unsigned iBlocks;                  // Index in Blöcke
  330.    vmRoot.pAct = vmRoot.pFirst;
  331.    for (iBlocks = 0;
  332.         iBlocks < vmRoot.cBlocks;
  333.         iBlocks++ )
  334.    {
  335.       pNext = vmRoot.pAct->pNext;
  336.       MemoryStatistics();
  337.       BlockStatistics(vmRoot.pAct, iBlocks + 1);
  338.            // wenn der Block noch gelocked ist,
  339.            // ist irgendwas faul
  340.       if (_vlockcnt(vmRoot.pAct -> hVM)) return FALSE;
  341.       _vfree(vmRoot.pAct->hVM);       // Free Node
  342.       free(vmRoot.pAct);
  343.                                       // Und weiter ...
  344.       vmRoot.pAct = pNext;
  345.    }
  346.    _vheapterm();                   // terminate the Mem Mng
  347.    return TRUE;
  348. }
  349.  
  350. /*-------------------------------------------------------*/
  351. /* Name:     VLPanicAbort                                */
  352. /* Funktion: Gibt nur eine kurze Meldung aus, falls es   */
  353. /*           Probleme mit dem VM geben sollte            */
  354. /*-------------------------------------------------------*/
  355. void VLPanicAbort(VMROOT vmRoot)            // Root Objekt
  356. {
  357.    printf("\nInside Panic abort");
  358.    printf("\n%u Blocks to release", vmRoot.cBlocks);
  359. }
  360.  
  361. /*-------------------------------------------------------*/
  362. /* Name:     BlockStatistics                             */
  363. /* Funktion: Gibt einige Informationen über einen Block  */
  364. /*           in der VL der Blöcke aus                    */
  365. /*-------------------------------------------------------*/
  366. void BlockStatistics(
  367.         VMNODE*  pvmNode,              // Zeiger auf Knoten
  368.         unsigned nNode )               // Knotennummer
  369. {
  370.    if (isDebug)
  371.    printf("\nNode#:%u Adress:%p"
  372.           "Handle:%lu LockCount:%u"
  373.           "Size:%u",
  374.           nNode,
  375.           pvmNode,
  376.           pvmNode -> hVM,
  377.           _vlockcnt(pvmNode -> hVM),
  378.           _vmsize(pvmNode -> hVM)
  379.          );
  380. }
  381. /*-------------------------------------------------------*/
  382. /* Name:     MemoryStatistics                            */
  383. /* Funktion: Gibt Informationen über den freien Heap aus.*/
  384. /*           Die Runtime Library enthält leider keine    */
  385. /*           Funktion, mit der man die Größe des freien  */
  386. /*           Heaps ermitteln kann. DOS liefert aber      */
  387. /*           netterweise genau diese zurück, falls man   */
  388. /*           mit der Funktion 48 0xFFFF Speicher an-     */
  389. /*           fordert. Gibt weiterhin Informationen über  */
  390. /*           den Stack aus.                              */
  391. /*-------------------------------------------------------*/
  392. void MemoryStatistics(void)
  393. {
  394.   if (isDebug)
  395.   {
  396.     long  cMemory;             // Freier Heap
  397.     union REGS inregs, outregs;
  398.     inregs.h.ah = 0x48;        // Funktion
  399.     inregs.x.bx = 0xFFFF;      // Speicheranforderungsgröße
  400.                                // (schlägt immer fehl!;
  401.                                // aber das soll so sein)
  402.     intdos(&inregs, &outregs); // Ab mit dem Interrupt
  403.                                // So, jetzt ist der freie
  404.                                // Heap bekannt
  405.     cMemory = (long)outregs.x.bx;
  406.     cMemory = cMemory * (long)16;
  407.     printf("\nHeap: %lu Stack:%u", cMemory, _stackavail());
  408.   }
  409. }
  410.  
  411. /*=======================================================*/
  412. /*                    Ende von VCOPY.C                   */
  413.