home *** CD-ROM | disk | FTP | other *** search
/ Mega CD-ROM 1 / megacd_rom_1.zip / megacd_rom_1 / MAGAZINE / MSJOURNA / MSJV3_3.ZIP / DLLCODE.ALL next >
Text File  |  1988-04-28  |  21KB  |  804 lines

  1. Microsoft Systems Journal
  2. Volume 3; Issue 3; May, 1988
  3.  
  4. Code Listings For:
  5.  
  6.     DLL_CHAT; DLL_LIB; CHATMEM
  7.     pp. 27-48
  8.  
  9.  
  10. Author(s): Ross M. Greenberg
  11. Title:     Design Concepts and Considerations in Building an OS/2
  12.            Dynamic-Link Library
  13.  
  14.  
  15.  
  16. Figure 7
  17. ========
  18.  
  19. DLL_CHAT DEF File
  20. =================
  21.  
  22.  
  23. IMPORTS CHATLIB.login
  24. IMPORTS CHATLIB.get_msg_cnt
  25. IMPORTS CHATLIB.send_msg
  26. IMPORTS CHATLIB.logout
  27. IMPORTS CHATLIB.get_msg
  28.  
  29.  
  30. ==============================================================================
  31.  
  32.  
  33.  
  34.  
  35.  
  36. /* Header file for CHAT */
  37.  
  38. struct gdtinfoarea{
  39.         unsigned long   time;
  40.         unsigned long   milliseconds;
  41.         unsigned char   hours;
  42.         unsigned char   minutes;
  43.         unsigned char   seconds;
  44.         unsigned char   hundreths;
  45.         unsigned        timezone;
  46.         unsigned        timer_interval;
  47.         unsigned char   day;
  48.         unsigned char   month;
  49.         unsigned        year;
  50.         unsigned char   day_of_week;
  51.         unsigned char   major_version;
  52.         unsigned char   minor_version;
  53.         unsigned char   revision_number;
  54.         unsigned char   current_screen_group;
  55.         unsigned char   max_num_of_screengrps;  
  56.         unsigned char   huge_selector_shift_count;
  57.         unsigned char   protect_mode_indicator;
  58.     unsigned    foreground_process_id;
  59.         unsigned char   dynamic_variation_flag;
  60.         unsigned char   maxwait;
  61.         unsigned        minimum_timeslice;
  62.         unsigned        maximum_timeslice;
  63.     unsigned    boot_drive;
  64.     unsigned char    reserved[32];
  65.  };
  66.  
  67.  
  68.  struct ldtinfoarea{
  69.         unsigned        current_process_pid;
  70.         unsigned        parent_pid;
  71.         unsigned        priority_of_current_thread;
  72.         unsigned        thread_id_of_current_thread;
  73.         unsigned        screen_group;
  74.         unsigned        subscreen_group;
  75.         unsigned        current_process_is_in_fg;
  76.  };
  77.  
  78.  
  79. ==============================================================================
  80.  
  81.  
  82. /********************************************************************
  83. *    DLL_CHAT.C  - A demonstration program using a demo DLL
  84. *
  85. *    (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
  86. *
  87. *    This is the main body of the CHAT program, interfacing with
  88. *    and calling the DLL as if it were a bunch of routines 
  89. *    available with a far call:  which it is!
  90. *
  91. *    Compile with:
  92. *    cl /c chat.c
  93. *    link chat,chat,,slibce+doscalls,chat
  94. *
  95. *    Remember: move the DLL itself into your DLL library directory
  96. *
  97. ********************************************************************/
  98.  
  99. #include    <stdio.h>
  100. #include    <stdlib.h>
  101. #include    "chat.h"
  102.  
  103. #define    TRUE    1
  104. #define    FALSE    0
  105. #define    OK    TRUE
  106. #define    NOT_OK    FALSE
  107.  
  108. #define    MAX_MSG        100
  109. #define    MAX_MSG_LEN    80
  110. #define    NULLP        (void *)NULL
  111.  
  112. /* The following OS/2 system calls are made in this module: */
  113.  
  114. extern far pascal dosexitlist();
  115. extern far pascal dossleep();
  116.  
  117.  
  118. /* The following DLL system calls are made in this module: */
  119.  
  120. extern far _loadds pascal login();
  121. extern far _loadds pascal logout();
  122. extern far _loadds pascal get_msg_cnt();
  123. extern far _loadds pascal get_msg();
  124. extern far _loadds pascal send_msg();
  125.  
  126.  
  127. /********************************************************************
  128. *    This is where the messages are stored, once received and 
  129. *    formatted. This could probably be replaced easily with a call 
  130. *    to calloc(), but then we wouldn't have to block on being a 
  131. *    background process
  132. ********************************************************************/
  133.  
  134. char    msg_array[MAX_MSG + 1][MAX_MSG_LEN];
  135.  
  136. /* Must be global so that before_death() can access it to logout */
  137.  
  138. int    my_id = 0;
  139.  
  140. #define    MAX_SLEEP    2
  141.  
  142. /********************************************************************
  143. *    before_death()
  144. *
  145. *    Called the coins are lowered onto the eyes of this invokation 
  146. *    of CHAT. Any exit will cause this routine to be called. After 
  147. *    this routine calls the DLL logout procedure, it removes calls 
  148. *    the next exitroutine in the exit list.
  149. ********************************************************************/
  150.  
  151. void    far    before_death()
  152. {
  153.     logout(my_id);
  154.     dosexitlist(3, before_death);
  155. }
  156.  
  157. /********************************************************************
  158. *    main()
  159. *
  160. *    After logging in (which returns a unique login id), the 
  161. *    before_death() routine is added onto the exitlist.  Then the 
  162. *    main loop:
  163. *
  164. *    If there are any messages, read them into out memory buffer 
  165. *    (provided there is room) and kick up the count.  After 
  166. *    retrieving all the msgs which will fit, call the display 
  167. *    routine for each msg. Zero the count of messages when done.
  168. *
  169. *    Every couple of seconds, sleep for a little while (as if a 
  170. *    human typing on a keyboard), then send the message to all 
  171. *    other members of CHAT.
  172. *
  173. *    CHAT can only be exited (in its current form) with a 
  174. *    control-C or error condition.
  175. ********************************************************************/
  176.  
  177. main()
  178. {
  179. int    msg_cnt = 0;
  180. int    msg_id = 0;
  181. int    lp_cnt;
  182. char    tmp_buf[MAX_MSG_LEN];
  183. int    m_cnt;
  184.  
  185.     printf("Logged into CHAT as user:%d\n", my_id = login());
  186.  
  187.     dosexitlist(1, before_death);
  188.  
  189.     while    (TRUE)
  190.     {
  191.         for (m_cnt = get_msg_cnt(my_id); m_cnt ; m_cnt--)
  192.         {
  193.             get_msg(my_id, (char far *)tmp_buf);
  194.              if    (msg_cnt <= MAX_MSG)
  195.                 sprintf(msg_array[msg_cnt++],"(%d)%s",my_id,tmp_buf);
  196.     }
  197.  
  198.         if    (ok_to_disp())
  199.         {
  200.             for (lp_cnt = 0 ; lp_cnt < msg_cnt; lp_cnt++)
  201.                 disp_msg(msg_array[lp_cnt]);
  202.             if    (msg_cnt > MAX_MSG)
  203.                 disp_msg("Looks like you might have lost some") 
  204.                 disp_msg(" messages while you were away\n");
  205.             msg_cnt = NULL;
  206.         }
  207.  
  208.         if    (rand() % (my_id + 1))
  209.         {
  210.             dossleep((long)(rand() % MAX_SLEEP) * 1000L);
  211.             sprintf(tmp_buf, "Test message #%d from Session #%d\n", 
  212.                     msg_id++, my_id);
  213.             if    (send_msg(my_id, (char far *)tmp_buf) == NOT_OK)
  214.                 printf("?Can't send a message....\n");
  215.         }
  216.     }
  217. }
  218.  
  219. disp_msg(ptr)
  220. char    *ptr;
  221. {
  222.     printf("%s", ptr);
  223.     fflush(stdout);
  224. }
  225.  
  226. extern far pascal dosgetinfoseg();
  227.  
  228. ok_to_disp()
  229. {
  230. struct gdtinfoarea far *gdt;
  231. struct ldtinfoarea far *ldt;
  232. unsigned    gseg;
  233. unsigned    lseg;
  234.  
  235.     dosgetinfoseg((char far *)&gseg, (char far *)&lseg);
  236.     gdt = (struct gdtinfoarea far *)((long)gseg << 16);
  237.     ldt = (struct ldtinfoarea far *)((long)lseg << 16);
  238.  
  239.     return( gdt->foreground_process_id == ldt->parent_pid);
  240. }
  241.  
  242.  
  243.  
  244.  
  245.  
  246. Figure 8
  247. ========
  248.  
  249.  
  250. CHATLIB DEF File
  251. ================
  252.  
  253.  
  254. LIBRARY CHATLIB INITGLOBAL
  255.  
  256. DATA SINGLE SHARED
  257.  
  258. EXPORTS login
  259. EXPORTS get_msg_cnt
  260. EXPORTS send_msg
  261. EXPORTS logout
  262. EXPORTS get_msg
  263.  
  264.  
  265. ==============================================================================
  266.  
  267.  
  268.  
  269. /********************************************************************
  270. *    CHATLIB.C  - A demonstration Dynamic Link Library
  271. *
  272. *    (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
  273. *
  274. *    This DLL, when used with the CHAT program acts as a central
  275. *    repository for all messages being passed
  276. *
  277. *    Compile with:
  278. *
  279. *    cl /AL /Au /Gs /c chatlib.c
  280. *
  281. *    Note -    Though broken here the following two lines are entered
  282. *            as one line:
  283. *
  284. *    link startup+chatlib+chatmem,chatlib.dll,,llibcdll+doscalls,
  285. *    chatlib/NOE
  286. *
  287. *    Remember to move the DLL itself into your DLL library directory
  288. *
  289. ********************************************************************/
  290.  
  291. #include    <stdio.h>
  292. #include    <stdlib.h>
  293. #include    <malloc.h>
  294. #include    <dos.h>
  295.  
  296. #define    TRUE    1
  297. #define    FALSE    0
  298. #define    OK    TRUE
  299. #define    NOT_OK    FALSE
  300.  
  301. #define    NULLP    ((char *)NULL)
  302. #define    GET_SEM    (dossemrequest(&semaphore, -1L))
  303. #define    RLS_SEM    (dossemclear(&semaphore))
  304.  
  305. /* The following OS/2 system calls are made in this module: */
  306.  
  307. extern far pascal dossemrequest();
  308. extern far pascal dossemclear();
  309.  
  310.  
  311. /* The following external calls are made in this module: */
  312.  
  313. char *my_calloc();
  314.  
  315.  
  316. /* This semaphore used to coordinate access to "critical" areas */
  317.  
  318. long    semaphore = 0;
  319.  
  320. /*******************************************************************
  321. *    This structure starts defines the members of the linked list
  322. *    which starts at master_ptr.  Once a structure is allocated,
  323. *    it is never released, although the character array member 
  324. *    msg_ptr points to will be released when the message is no longer 
  325. *    needed
  326. ********************************************************************/
  327. #define    MSG    struct    _msg
  328. MSG{
  329.     MSG            *next_ptr;    /* Point to next MSG, or NULLM      */
  330.     char        *msg_ptr;    /* Point to the actual message      */
  331.     int            msg_len;    /* length of the message - optional */
  332.     unsigned    f_word;        /* flag_word. When set to 0xfff     */
  333.                             /* all chat members have seen this  */
  334.                             /* message, so it can be freed      */
  335.     };
  336.  
  337. int    flag_word = 0xffff;    /* This is the word that f_word is  */
  338.                             /* set to initially. It is modified */
  339.                             /* so that each bit is "off" if that*/
  340.                             /* "user" is logged in              */
  341.              
  342. #define    NULLM    ((MSG *)NULL)
  343. MSG    *master_ptr = NULLM;    /* Where the linked list begins    */
  344.  
  345. /********************************************************************
  346. *    new_msg_struct(pointer to last MSG)
  347. *
  348. *    Allocates a new MSG, initializes the contents of the structure, 
  349. *    and sets the linked list if not the first time called 
  350. *    (last_msg != NULLM)
  351. *
  352. *    Returns a pointer to the structure allocated, NULLM if an error
  353. ********************************************************************/
  354.  
  355. MSG    *new_msg_struct(MSG *last_msg)
  356. {
  357. MSG    *tmp_ptr;
  358.  
  359.     if    ((tmp_ptr = (MSG *)my_calloc(sizeof(MSG), 1)) == NULLM)
  360.         return(NULLM);
  361.  
  362.     tmp_ptr->next_ptr = NULLM;
  363.  
  364.     tmp_ptr->msg_ptr = NULLP;
  365.     tmp_ptr->msg_len = NULL;
  366.  
  367.     tmp_ptr->f_word = flag_word;
  368.  
  369.     if    (last_msg != NULLM)
  370.         last_msg->next_ptr = tmp_ptr;
  371.  
  372.     return(tmp_ptr);
  373. }
  374.  
  375.  
  376. /********************************************************************
  377. *    initialize()
  378. *
  379. *    Called either by the initialization routine of the DLL, or by the
  380. *    first login. It allocates the first MSG structure, then allocates
  381. *    and sets up for the next member
  382. ********************************************************************/
  383.  
  384. void far _loadds pascal initialize()
  385. {
  386.  
  387.     if    ((master_ptr = new_msg_struct(NULLP)) == NULLM)
  388.     {
  389.         printf("Couldn't allocate MSG memory for header...\n");
  390.         exit(1);
  391.     }
  392.  
  393.     new_msg_struct(master_ptr);
  394. }
  395.  
  396. /********************************************************************
  397. *    login()
  398. *
  399. *    If the master MSG structure hasn't been allocated already by
  400. *    and earlier call to initialize() (by the DLL initialize routine),
  401. *    then make the call now.  Memory has already been allocated, 
  402. *    therefore, so now give ourselves access to the segment we've 
  403. *    allocated.
  404. *
  405. *    Get the next free bit slot in the flag word, set it to indicate
  406. *    it's in use, then return our login id.
  407. ********************************************************************/
  408.  
  409. int far _loadds pascal login()
  410. {
  411. int    log_id;
  412. int    tmp_msk;
  413.  
  414.     if    (master_ptr == NULLM)
  415.     {
  416.         printf("Init in login\n");
  417.         initialize();
  418.     }
  419.  
  420.     my_getseg();
  421.  
  422.     GET_SEM;
  423.     for (log_id= 0 ; log_id < 16 ; log_id++)
  424.     {
  425.         tmp_msk = mask(log_id);
  426.         if    (flag_word & tmp_msk)
  427.         {
  428.             flag_word &= ~tmp_msk;
  429.             RLS_SEM;
  430.             return(log_id);
  431.         }
  432.  
  433.     }
  434.     RLS_SEM;
  435.  
  436.     printf("Login slots all used up!\n");
  437.     exit(1);
  438. }
  439.  
  440. /********************************************************************
  441. *    get_msg_cnt(login_id)
  442. *
  443. *    For every MSG structure in the linked list with an associated
  444. *    message attached to it, increment a counter if the id in question
  445. *    hasn't received it yet, then return that counter when we fall off
  446. *    the end.  
  447. ********************************************************************/
  448.  
  449. int far _loadds pascal get_msg_cnt(int id)
  450. {
  451. MSG    *tmp_ptr;
  452. int    tmp_cnt = 0;
  453. int    tmp_msk = mask(id);
  454.  
  455.  
  456.     GET_SEM;
  457.     for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
  458.     {
  459.         if    (!(tmp_ptr->f_word & tmp_msk))
  460.             if    (tmp_ptr->msg_len)
  461.                 tmp_cnt++;
  462.     }
  463.  
  464.     RLS_SEM;
  465.     return(tmp_cnt);
  466. }
  467.  
  468. /********************************************************************
  469. *    send_msg(login_id, pointer_to_message)
  470. *
  471. *    If there are no other "chatter's" logged in, simply return.
  472. *    (Flag_word or'ed with our mask would be 0xfff)
  473. *
  474. *    Find a free MSG structure (guaranteed to have at least one, since
  475. *    every write leaves a free one allocated if its the last one in 
  476. *    the linked list.  
  477. *
  478. *    Allocate memory for the message, copy the message into it, then
  479. *    assign the pointer in the structure and the length of the message.
  480. *    Finally, allocate a new structure if required.
  481. ********************************************************************/
  482.  
  483. int far _loadds pascal send_msg(int id, char far *ptr)
  484. {
  485. MSG    *tmp_ptr = master_ptr;
  486. int    tmp_len = strlen(ptr) + 1;
  487.  
  488.  
  489.     if    ((flag_word | mask(id)) == 0xffff)
  490.         return(OK);
  491.  
  492.     GET_SEM;
  493.     while    (tmp_ptr->msg_len)
  494.         tmp_ptr = tmp_ptr->next_ptr;
  495.  
  496.     if    ((tmp_ptr->msg_ptr = my_calloc(tmp_len, 1)) == NULLP)
  497.     {
  498.         printf("Can't allocate %d bytes for msg\n", tmp_len);
  499.         RLS_SEM;
  500.         return(NOT_OK);
  501.     }
  502.  
  503.     strcpy(tmp_ptr->msg_ptr, ptr);
  504.     tmp_ptr->msg_len = tmp_len;
  505.     tmp_ptr->f_word = (flag_word | mask(id));
  506.  
  507.     if    (tmp_ptr->next_ptr == NULLM)
  508.     {
  509.         if    (new_msg_struct(tmp_ptr) == NULLM)
  510.         {
  511.             printf("Can't allocate new MSG_header\n");
  512.             free_msg(tmp_ptr);
  513.             RLS_SEM;
  514.             return(NOT_OK);
  515.         }
  516.     }
  517.  
  518.     RLS_SEM;
  519.     return(OK);
  520. }
  521.  
  522.  
  523. /********************************************************************
  524. *    logout(login_id)
  525. *
  526. *    Mark every mesage as read (freeing them if now "totally" read),
  527. *    reset the flag word, and then indicate that the logout worked.
  528. ********************************************************************/
  529.  
  530. int far _loadds pascal logout(int id)
  531. {
  532. MSG    *tmp_ptr;
  533. int    tmp_msk = mask(id);
  534.  
  535.     GET_SEM;
  536.     for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
  537.         mark_msg(id, tmp_ptr);
  538.  
  539.     flag_word |= mask(id);
  540.  
  541.     RLS_SEM;
  542.  
  543.     printf("In logout ... Hit a Key:");fflush(stdout);
  544.     getch();
  545.     printf("\n\n\n\n");
  546.  
  547.     return(0);
  548. }
  549.  
  550. /********************************************************************
  551. *    get_msg(login_id, pointer to buffer)
  552. *
  553. *    Find the first message the login_id hasn;t read, then
  554. *    strcpy it into the buffer supplied. Then mark the message as
  555. *    read (freeing as required).
  556. ********************************************************************/
  557.  
  558. int far _loadds pascal get_msg(int id, char far *ptr)
  559. {
  560. MSG    *tmp_ptr = master_ptr;
  561. int    tmp_msk = mask(id);
  562.  
  563.  
  564.  
  565.     GET_SEM;
  566.     for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
  567.     {
  568.         if    (!(tmp_ptr->f_word & tmp_msk))
  569.         {
  570.             strcpy(ptr, tmp_ptr->msg_ptr);
  571.             mark_msg(id, tmp_ptr);
  572.             RLS_SEM;
  573.             return(TRUE);
  574.         }
  575.     }
  576.     RLS_SEM;
  577.     return(FALSE);
  578. }
  579.  
  580. /********************************************************************
  581. *    mark_msg(login id, pointer to message structure)
  582. *
  583. *    Mark our bit in the MSG f_word as set.  If then set to 0xffff,
  584. *    the message is "totally" read, so free it.
  585. *
  586. *    ******************************************************************
  587. *
  588. *    free(pointer to message structure)
  589. *      
  590. *    If there is a string associated with this structure, free the
  591. *    memory so used, then zero out the pointer and the msg_len
  592. ********************************************************************/
  593.  
  594. mark_msg(int id, MSG *ptr)
  595. {
  596.     ptr->f_word |= mask(id);
  597.     if    (ptr->f_word == 0xffff)
  598.         free_msg(ptr);
  599. }
  600.  
  601. free_msg(MSG *ptr)
  602. {
  603.     if    (ptr->msg_ptr)
  604.         my_free(ptr->msg_ptr);
  605.      ptr->msg_ptr = NULLP;
  606.     ptr->msg_len = NULL;
  607. }
  608.  
  609.                         /* GENERAL ROUTINES */
  610.  
  611. /* This routine merely returns with the bit corresponding 
  612.  * to our login set
  613.  */
  614.  
  615. mask(int log_id)
  616. {
  617.     return(1 << (log_id - 1));
  618. }
  619.  
  620.  
  621. ==============================================================================
  622.  
  623.  
  624. Additional Module for CHATLIB
  625. =============================
  626.  
  627.  
  628. /********************************************************************
  629. *    CHATMEM.C  - Memory allocation routines for shared DLL memory
  630. *
  631. *    (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
  632. *
  633. *    This module conatins three functions. Allocation of memory,
  634. *    de-allocation of memory and the getseg call.
  635. *
  636. *    The current ANSI calloc/alloc/malloc sequence does not allow for
  637. *    an additional parameter to specify if memory requested through
  638. *    these functions is to be sharable or private. Therefore the MSC
  639. *    library calls all allocate private memory.
  640. *
  641. *    These routines allocate a 64K chunk of memory, requested from OS/2
  642. *    as a sharable chunk, then dole it out using the DosSub allocation
  643. *    calls.
  644. *
  645. *    Only one 64K chunk is allocated: if more memory is desired an
  646. *    additional call to dosallocseg would have to be made and all 
  647. *    sessions already logged in given access to the chunk.  Out of 
  648. *    laziness, that was not done for these demonsttration routines.
  649. *
  650. *
  651. *    Compile with:
  652. *
  653. *    cl /AL /Au /Gs /c chatmem.c
  654. *
  655. *    Note -    Though broken here, the following two lines are entered
  656. *            as one line:
  657. *
  658. *    link startup+chatlib+chatmem,chatlib.dll,,llibcdll+doscalls,
  659. *    chatlib/NOE
  660. *
  661. *    Remember to move the DLL itself into your DLL library directory
  662. *
  663. ********************************************************************/
  664.  
  665. #include    <stdio.h>
  666. #include    <stdlib.h>
  667. #include    <malloc.h>
  668. #include    <dos.h>
  669.  
  670. #define    TRUE    1
  671. #define    FALSE    0
  672.  
  673. /* The following OS/2 system calls are made in this module: */
  674.  
  675. extern far pascal dosallocseg();
  676. extern far pascal dosfreeseg();
  677. extern far pascal dossuballoc();
  678. extern far pascal dossubset();
  679. extern far pascal dossubfree();
  680. extern far pascal dosgetseg();
  681. extern far pascal dossemrequest();
  682. extern far pascal dossemclear();
  683.  
  684.  
  685. #define    NULLP    (char *)NULL
  686.  
  687.  
  688. /*    This semaphore is so that we don't hurt ourselves as we allocate
  689.  *    and deallocate memory
  690.  */
  691.  
  692. long    memory_semaphore = NULL;
  693.  
  694. /*    This is the actual selector which the 64K dosallocseg() 
  695.  * call returns
  696.  */
  697.  
  698. unsigned major_selector = NULL;
  699.  
  700. /********************************************************************
  701. *    my_calloc(number_of_items,size_of_item)
  702. *
  703. *    Emulates the more typical calloc call, but returns memory which
  704. *    can later be allocated as sharable.
  705. *
  706. *    After the first call (which causes a 64K chunk to be allocated),
  707. *    all subsequent calls cause a dossuballoc call to be made, and
  708. *    a long pointer to the returned memory to be created and returned
  709. *
  710. *    The 64K chunk must be initialized by the dossubset call before it
  711. *    can be used by other dossub functions.
  712. *
  713. *    Because the dossubfree call requires a size, the size requested
  714. *    plus the sizeof an int is actually allocated and the size of the
  715. *    total request is then stored in the first two bytes of the 
  716. *    returned character array.  The ptr returned, however, is this 
  717. *    memory location plus the initial sizeof and int -- therefore the 
  718. *    bookkeeping is transparent to the application task.
  719. ********************************************************************/
  720.  
  721. char * 
  722. my_calloc(size1, size2)
  723. int    size1;
  724. int    size2;
  725. {
  726. unsigned    long    selector;
  727. int    stat;
  728. char    *ptr;
  729. int    sizeit = (size1 * size2) + sizeof(int);
  730.  
  731.     dossemrequest(&memory_semaphore, -1L);
  732.     if    (!major_selector)
  733.     {
  734.         if    (stat = dosallocseg(0, &major_selector, 3))
  735.         {
  736.             printf("dosalloc error:%d\n", stat);
  737.             dossemclear(&memory_semaphore);
  738.             return(NULLP);
  739.         }
  740.  
  741.         if    (stat = dossubset(major_selector, 1, 0))
  742.         {
  743.             printf("Error in dossubset:%d\n", stat);
  744.             dossemclear(&memory_semaphore);
  745.             return(NULLP);
  746.         }
  747.     }
  748.  
  749.     selector = 0;
  750.     if    (stat = dossuballoc(major_selector, &selector, sizeit))
  751.     {
  752.         printf("dossuballoc error:%d\n", stat);
  753.         dossemclear(&memory_semaphore);
  754.         return(NULLP);
  755.     }
  756.  
  757.     dossemclear(&memory_semaphore);
  758.     ptr = (char *)(((long)major_selector << 16) + (long)selector);
  759.     memset(ptr, (char)NULL, sizeit);
  760.     *(int *)ptr = sizeit;
  761.     return(ptr + sizeof(int));
  762. }
  763.  
  764. /********************************************************************
  765. *    my_free(pointer_to_a_character_array_previously_my_calloc'ed)
  766. *
  767. *    Subtract sizeof an int from the pointer, dereference as an
  768. *    int, then free that number of bytes.
  769. *
  770. ********************************************************************/
  771.  
  772. my_free(ptr)
  773. char    *ptr;
  774. {
  775. int    stat;
  776.  
  777.     ptr -= sizeof(int);
  778.  
  779.     dossemrequest(&memory_semaphore, -1L);
  780.     if (stat = dossubfree(major_selector, FP_OFF(ptr), *(int *)ptr))
  781.     {
  782.         printf("Error freeing: %lx\n", ptr);
  783.         exit(1);
  784.     }
  785.     dossemclear(&memory_semaphore);
  786. }
  787.  
  788. /********************************************************************
  789. *    my_getseg()
  790. *
  791. *    Causes the memory affilaited with the major_selector to become
  792. *    accessable to this process.
  793. ********************************************************************/
  794.  
  795. my_getseg()
  796. {
  797. int    stat;
  798.  
  799.     if    (stat=dosgetseg(major_selector))
  800.         printf("Error on getseg:%d\n", stat);
  801.     return(stat);
  802. }
  803.  
  804.