home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / msj / msjv3_3 / dllcode / chatlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-02  |  8.8 KB  |  351 lines

  1. /********************************************************************
  2. *    CHATLIB.C  - A demonstration Dynamic Link Library
  3. *
  4. *    (C) 1988, By Ross M. Greenberg for Microsoft Systems Journal
  5. *
  6. *    This DLL, when used with the CHAT program acts as a central
  7. *    repository for all messages being passed
  8. *
  9. *    Compile with:
  10. *
  11. *    cl /AL /Au /Gs /c chatlib.c
  12. *
  13. *    Note -    Though broken here the following two lines are entered
  14. *            as one line:
  15. *
  16. *    link startup+chatlib+chatmem,chatlib.dll,,llibcdll+doscalls,
  17. *    chatlib/NOE
  18. *
  19. *    Remember to move the DLL itself into your DLL library directory
  20. *
  21. ********************************************************************/
  22.  
  23. #include    <stdio.h>
  24. #include    <stdlib.h>
  25. #include    <malloc.h>
  26. #include    <dos.h>
  27.  
  28. #define    TRUE    1
  29. #define    FALSE    0
  30. #define    OK    TRUE
  31. #define    NOT_OK    FALSE
  32.  
  33. #define    NULLP    ((char *)NULL)
  34. #define    GET_SEM    (dossemrequest(&semaphore, -1L))
  35. #define    RLS_SEM    (dossemclear(&semaphore))
  36.  
  37. /* The following OS/2 system calls are made in this module: */
  38.  
  39. extern far pascal dossemrequest();
  40. extern far pascal dossemclear();
  41.  
  42.  
  43. /* The following external calls are made in this module: */
  44.  
  45. char *my_calloc();
  46.  
  47.  
  48. /* This semaphore used to coordinate access to "critical" areas */
  49.  
  50. long    semaphore = 0;
  51.  
  52. /*******************************************************************
  53. *    This structure starts defines the members of the linked list
  54. *    which starts at master_ptr.  Once a structure is allocated,
  55. *    it is never released, although the character array member 
  56. *    msg_ptr points to will be released when the message is no longer 
  57. *    needed
  58. ********************************************************************/
  59. #define    MSG    struct    _msg
  60. MSG{
  61.     MSG            *next_ptr;    /* Point to next MSG, or NULLM      */
  62.     char        *msg_ptr;    /* Point to the actual message      */
  63.     int            msg_len;    /* length of the message - optional */
  64.     unsigned    f_word;        /* flag_word. When set to 0xfff     */
  65.                             /* all chat members have seen this  */
  66.                             /* message, so it can be freed      */
  67.     };
  68.  
  69. int    flag_word = 0xffff;    /* This is the word that f_word is  */
  70.                             /* set to initially. It is modified */
  71.                             /* so that each bit is "off" if that*/
  72.                             /* "user" is logged in              */
  73.              
  74. #define    NULLM    ((MSG *)NULL)
  75. MSG    *master_ptr = NULLM;    /* Where the linked list begins    */
  76.  
  77. /********************************************************************
  78. *    new_msg_struct(pointer to last MSG)
  79. *
  80. *    Allocates a new MSG, initializes the contents of the structure, 
  81. *    and sets the linked list if not the first time called 
  82. *    (last_msg != NULLM)
  83. *
  84. *    Returns a pointer to the structure allocated, NULLM if an error
  85. ********************************************************************/
  86.  
  87. MSG    *new_msg_struct(MSG *last_msg)
  88. {
  89. MSG    *tmp_ptr;
  90.  
  91.     if    ((tmp_ptr = (MSG *)my_calloc(sizeof(MSG), 1)) == NULLM)
  92.         return(NULLM);
  93.  
  94.     tmp_ptr->next_ptr = NULLM;
  95.  
  96.     tmp_ptr->msg_ptr = NULLP;
  97.     tmp_ptr->msg_len = NULL;
  98.  
  99.     tmp_ptr->f_word = flag_word;
  100.  
  101.     if    (last_msg != NULLM)
  102.         last_msg->next_ptr = tmp_ptr;
  103.  
  104.     return(tmp_ptr);
  105. }
  106.  
  107.  
  108. /********************************************************************
  109. *    initialize()
  110. *
  111. *    Called either by the initialization routine of the DLL, or by the
  112. *    first login. It allocates the first MSG structure, then allocates
  113. *    and sets up for the next member
  114. ********************************************************************/
  115.  
  116. void far _loadds pascal initialize()
  117. {
  118.  
  119.     if    ((master_ptr = new_msg_struct(NULLP)) == NULLM)
  120.     {
  121.         printf("Couldn't allocate MSG memory for header...\n");
  122.         exit(1);
  123.     }
  124.  
  125.     new_msg_struct(master_ptr);
  126. }
  127.  
  128. /********************************************************************
  129. *    login()
  130. *
  131. *    If the master MSG structure hasn't been allocated already by
  132. *    and earlier call to initialize() (by the DLL initialize routine),
  133. *    then make the call now.  Memory has already been allocated, 
  134. *    therefore, so now give ourselves access to the segment we've 
  135. *    allocated.
  136. *
  137. *    Get the next free bit slot in the flag word, set it to indicate
  138. *    it's in use, then return our login id.
  139. ********************************************************************/
  140.  
  141. int far _loadds pascal login()
  142. {
  143. int    log_id;
  144. int    tmp_msk;
  145.  
  146.     if    (master_ptr == NULLM)
  147.     {
  148.         printf("Init in login\n");
  149.         initialize();
  150.     }
  151.  
  152.     my_getseg();
  153.  
  154.     GET_SEM;
  155.     for (log_id= 0 ; log_id < 16 ; log_id++)
  156.     {
  157.         tmp_msk = mask(log_id);
  158.         if    (flag_word & tmp_msk)
  159.         {
  160.             flag_word &= ~tmp_msk;
  161.             RLS_SEM;
  162.             return(log_id);
  163.         }
  164.  
  165.     }
  166.     RLS_SEM;
  167.  
  168.     printf("Login slots all used up!\n");
  169.     exit(1);
  170. }
  171.  
  172. /********************************************************************
  173. *    get_msg_cnt(login_id)
  174. *
  175. *    For every MSG structure in the linked list with an associated
  176. *    message attached to it, increment a counter if the id in question
  177. *    hasn't received it yet, then return that counter when we fall off
  178. *    the end.  
  179. ********************************************************************/
  180.  
  181. int far _loadds pascal get_msg_cnt(int id)
  182. {
  183. MSG    *tmp_ptr;
  184. int    tmp_cnt = 0;
  185. int    tmp_msk = mask(id);
  186.  
  187.  
  188.     GET_SEM;
  189.     for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
  190.     {
  191.         if    (!(tmp_ptr->f_word & tmp_msk))
  192.             if    (tmp_ptr->msg_len)
  193.                 tmp_cnt++;
  194.     }
  195.  
  196.     RLS_SEM;
  197.     return(tmp_cnt);
  198. }
  199.  
  200. /********************************************************************
  201. *    send_msg(login_id, pointer_to_message)
  202. *
  203. *    If there are no other "chatter's" logged in, simply return.
  204. *    (Flag_word or'ed with our mask would be 0xfff)
  205. *
  206. *    Find a free MSG structure (guaranteed to have at least one, since
  207. *    every write leaves a free one allocated if its the last one in 
  208. *    the linked list.  
  209. *
  210. *    Allocate memory for the message, copy the message into it, then
  211. *    assign the pointer in the structure and the length of the message.
  212. *    Finally, allocate a new structure if required.
  213. ********************************************************************/
  214.  
  215. int far _loadds pascal send_msg(int id, char far *ptr)
  216. {
  217. MSG    *tmp_ptr = master_ptr;
  218. int    tmp_len = strlen(ptr) + 1;
  219.  
  220.  
  221.     if    ((flag_word | mask(id)) == 0xffff)
  222.         return(OK);
  223.  
  224.     GET_SEM;
  225.     while    (tmp_ptr->msg_len)
  226.         tmp_ptr = tmp_ptr->next_ptr;
  227.  
  228.     if    ((tmp_ptr->msg_ptr = my_calloc(tmp_len, 1)) == NULLP)
  229.     {
  230.         printf("Can't allocate %d bytes for msg\n", tmp_len);
  231.         RLS_SEM;
  232.         return(NOT_OK);
  233.     }
  234.  
  235.     strcpy(tmp_ptr->msg_ptr, ptr);
  236.     tmp_ptr->msg_len = tmp_len;
  237.     tmp_ptr->f_word = (flag_word | mask(id));
  238.  
  239.     if    (tmp_ptr->next_ptr == NULLM)
  240.     {
  241.         if    (new_msg_struct(tmp_ptr) == NULLM)
  242.         {
  243.             printf("Can't allocate new MSG_header\n");
  244.             free_msg(tmp_ptr);
  245.             RLS_SEM;
  246.             return(NOT_OK);
  247.         }
  248.     }
  249.  
  250.     RLS_SEM;
  251.     return(OK);
  252. }
  253.  
  254.  
  255. /********************************************************************
  256. *    logout(login_id)
  257. *
  258. *    Mark every mesage as read (freeing them if now "totally" read),
  259. *    reset the flag word, and then indicate that the logout worked.
  260. ********************************************************************/
  261.  
  262. int far _loadds pascal logout(int id)
  263. {
  264. MSG    *tmp_ptr;
  265. int    tmp_msk = mask(id);
  266.  
  267.     GET_SEM;
  268.     for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
  269.         mark_msg(id, tmp_ptr);
  270.  
  271.     flag_word |= mask(id);
  272.  
  273.     RLS_SEM;
  274.  
  275.     printf("In logout ... Hit a Key:");fflush(stdout);
  276.     getch();
  277.     printf("\n\n\n\n");
  278.  
  279.     return(0);
  280. }
  281.  
  282. /********************************************************************
  283. *    get_msg(login_id, pointer to buffer)
  284. *
  285. *    Find the first message the login_id hasn;t read, then
  286. *    strcpy it into the buffer supplied. Then mark the message as
  287. *    read (freeing as required).
  288. ********************************************************************/
  289.  
  290. int far _loadds pascal get_msg(int id, char far *ptr)
  291. {
  292. MSG    *tmp_ptr = master_ptr;
  293. int    tmp_msk = mask(id);
  294.  
  295.  
  296.  
  297.     GET_SEM;
  298.     for(tmp_ptr = master_ptr; tmp_ptr; tmp_ptr = tmp_ptr->next_ptr)
  299.     {
  300.         if    (!(tmp_ptr->f_word & tmp_msk))
  301.         {
  302.             strcpy(ptr, tmp_ptr->msg_ptr);
  303.             mark_msg(id, tmp_ptr);
  304.             RLS_SEM;
  305.             return(TRUE);
  306.         }
  307.     }
  308.     RLS_SEM;
  309.     return(FALSE);
  310. }
  311.  
  312. /********************************************************************
  313. *    mark_msg(login id, pointer to message structure)
  314. *
  315. *    Mark our bit in the MSG f_word as set.  If then set to 0xffff,
  316. *    the message is "totally" read, so free it.
  317. *
  318. *    ******************************************************************
  319. *
  320. *    free(pointer to message structure)
  321. *      
  322. *    If there is a string associated with this structure, free the
  323. *    memory so used, then zero out the pointer and the msg_len
  324. ********************************************************************/
  325.  
  326. mark_msg(int id, MSG *ptr)
  327. {
  328.     ptr->f_word |= mask(id);
  329.     if    (ptr->f_word == 0xffff)
  330.         free_msg(ptr);
  331. }
  332.  
  333. free_msg(MSG *ptr)
  334. {
  335.     if    (ptr->msg_ptr)
  336.         my_free(ptr->msg_ptr);
  337.      ptr->msg_ptr = NULLP;
  338.     ptr->msg_len = NULL;
  339. }
  340.  
  341.                         /* GENERAL ROUTINES */
  342.  
  343. /* This routine merely returns with the bit corresponding 
  344.  * to our login set
  345.  */
  346.  
  347. mask(int log_id)
  348. {
  349.     return(1 << (log_id - 1));
  350. }
  351.