home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 201_01 / nodupe.c < prev    next >
Text File  |  1979-12-31  |  9KB  |  246 lines

  1. /*--------------------------------------------------------------------------*/
  2. /*                                        */
  3. /* nodupe.c  - module for use with TSR programs which will check        */
  4. /*           environments in memory to see if the same file has already   */
  5. /*           been run.  Keeps user from installing resident programs        */
  6. /*           more than once.                            */
  7. /*                                        */
  8. /*     version 1.0 - 3/6/86                            */
  9. /*                                        */
  10. /*     version 1.1 - 3/9/86                            */
  11. /*       changed environment buffer to heap storage so it can be        */
  12. /*       disposed of later.                            */
  13. /*                                        */
  14. /* The program works by first finding the name of the program just invoked  */
  15. /* in the environment area set up for it by DOS.  It then traces back to    */
  16. /* the start of command.com by working backwards along the linked list of   */
  17. /* parents.  The pointer to a program's parent process is contained at      */
  18. /* offset 16H in the program segment prefix. Tracing this chain back until  */
  19. /* it points to itself will locate the psp of command.com. From there, the  */
  20. /* program traces the DOS memory control blocks forward. It searches for a  */
  21. /* program segment prefix by looking for the bytes CD 20, which are the     */
  22. /* INT 20 instruction at the beginning of every psp. When a psp is located, */
  23. /* then the environment area for that program is located by using the        */
  24. /* pointer at offset 2C. The name of this program is then found and com-    */
  25. /* pared to the name of the current program. If a match is found, then the  */
  26. /* routine returns a TRUE value, indicating it has found a matching name.   */
  27. /* If the names don't match, the routine continues checking blocks until    */
  28. /* it finds a match or reaches the end of the memory control block chain.   */
  29. /*                                        */
  30. /* This code is designed to be included in terminate-and-stay-resident        */
  31. /* (TSR) programs, or to be linked in as an external module. If it is        */
  32. /* linked as an external module, it will require the inclusion of the        */
  33. /* external declaration such as:                        */
  34. /*                                        */
  35. /*     extern  int  check_dupe();                        */
  36. /*                                        */
  37. /*---------------------------------------------Brian Irvine-----------------*/
  38.  
  39. #include   <stdio.h>
  40.  
  41. /* The pointer to the parent which invoked a process is located at offset   */
  42. /* 0x16 in the PSP of the current process.                    */
  43.  
  44. #define    PARENT  0x16
  45. #define    ENVIRON 0x2C
  46. #define    PSPID   0x20CD
  47. #define    SIZEOFF 3
  48. #define    OWNROFF 1
  49.  
  50. typedef    char bool;
  51.  
  52. unsigned find_head ();               /* finds beginning of mcb chain */
  53. unsigned freeall ();
  54. char   *malloc ();
  55. char   *find_name ();               /* returns pointer to name of current */
  56.                        /* program */
  57. bool   check_end ();
  58.  
  59. /*----- Check to see if this program is already in memory ------------------*/
  60. /*                                        */
  61. /*     Check environments in memory to see if the calling program has been  */
  62. /*     installed already.  Return 0 if no match is found, return 1 if a     */
  63. /*     matching name was found.                         */
  64. /*                                        */
  65. /*--------------------------------------------------------------------------*/
  66.  
  67. int    check_dupe()
  68. {
  69.    unsigned    owner, psp, mcb;
  70.    unsigned    head, blksize;
  71.    unsigned    chkword, envseg;
  72.    char        *env, *name, *lbuf;
  73.    bool        end = FALSE;
  74.  
  75.    lbuf = malloc ( 256 );      /* get storage for environment strings */
  76.    name = malloc ( 15 );       /* get storage for file name */
  77.    psp = _showcs() - 0x10;
  78.    mcb = psp - 1;
  79. /*     Locate the local environment and copy it to lbuf             */
  80.  
  81.    _lmove ( 2, ENVIRON, psp, &envseg, _showds() );
  82.    _lmove ( 256, 0, envseg, lbuf, _showds() );
  83.  
  84. /*     Then locate the program name at the end of the pathname            */
  85.  
  86.    env = find_name ( lbuf );
  87.    strcpy ( name, env );
  88.  
  89.    head = find_head (psp);           /* find the psp of command.com */
  90.    mcb = head - 1;               /* locate memory control block */
  91.  
  92.    /* get size of block, add to current segment address + 1    */
  93.    /* to skip over the environment block for command.com.      */
  94.  
  95.    _lmove ( 2, SIZEOFF, mcb, &blksize, _showds() );
  96.    mcb += blksize;
  97.    mcb++;
  98.    end = check_end (mcb);
  99.    if ( end )
  100.        {
  101.        freeall ();               /* deallocate memory */
  102.        return ( FALSE );           /* and return 'not found' if we are.   */
  103.        }
  104.  
  105.    /* now search for the next psp by looking for bytes CD 20 immediately  */
  106.    /* after the end of the current mcb.                   */
  107.  
  108.    while ( 1 )
  109.        {
  110.  
  111.    /* skip over unused blocks */
  112.  
  113.        _lmove ( 2, OWNROFF, mcb, &owner, _showds() );
  114.        while ( !owner )
  115.        {
  116.        _lmove ( 2, SIZEOFF, mcb, &blksize, _showds() );
  117.        mcb += blksize;
  118.        mcb++;
  119.        end = check_end ( mcb );
  120.        if ( end )
  121.            {
  122.            freeall ();
  123.            return ( FALSE );
  124.            }
  125.        _lmove ( 2, OWNROFF, mcb, &owner, _showds() );
  126.        }   /* end while */
  127.  
  128.     /* found a used memory block, so find the environment and copy it */
  129.     /* into the local buffer and find the file name. If it's the same */
  130.     /* as the name we are looking for, return with flag set. */
  131.  
  132.        _lmove ( 2, 16, mcb, &chkword, _showds() );
  133.        if ( chkword == PSPID )
  134.        {
  135.        psp = mcb + 1;
  136.        _lmove ( 2, ENVIRON, psp, &envseg, _showds() );
  137.        _lmove ( 256, 0, envseg, lbuf, _showds() );
  138.        env = find_name ( lbuf );
  139.        if ( !strcmp ( env, name ) )  /* zero result means env = name */
  140.            {
  141.            freeall ();
  142.            return ( TRUE );
  143.            }
  144.        }   /* end if */
  145.  
  146.        /* fall through to here if no match found and not at end of chain */
  147.        /* so calculate segment address of next mcb */
  148.  
  149.        _lmove ( 2, SIZEOFF, mcb, &blksize, _showds() );
  150.        mcb += blksize;
  151.        mcb++;
  152.        end = check_end ( mcb );
  153.        if ( end )
  154.        {
  155.        freeall();
  156.        return ( FALSE );
  157.        }
  158.  
  159.        }   /* end while */
  160.  
  161. }
  162.  
  163.  
  164. /*--------------------------------------------------------------------------*/
  165. /*              Support Routines                    */
  166. /*--------------------------------------------------------------------------*/
  167.  
  168.  
  169.  
  170. /*----- Find the psp of Command.com ----------------------------------------*/
  171. /*                                        */
  172. /*     Start at the psp of the current program and work backwards using     */
  173. /*     offset 0x16 in the psp to find the parent which invoked this        */
  174. /*     program.  This should only take one iteration, but may take more.    */
  175. /*     When pointer points to itself, we have found the psp of command.com. */
  176. /*     Return with the segment address of command.com's psp.                */
  177. /*                                        */
  178. /*--------------------------------------------------------------------------*/
  179.  
  180. unsigned   find_head(psp)
  181. unsigned   psp;
  182. {
  183.    unsigned    old_parent, new_parent;
  184.  
  185.    old_parent = new_parent = 0;
  186.    _lmove ( 2, PARENT, psp, &new_parent, _showds() );
  187.    while ( old_parent != new_parent )
  188.        {
  189.        old_parent = new_parent;
  190.        psp = old_parent;
  191.        _lmove ( 2, PARENT, psp, &new_parent, _showds() );
  192.        }
  193.    return ( new_parent );
  194.  
  195. }
  196.  
  197.  
  198. /*----- Find program name in environment area ------------------------------*/
  199. /*                                        */
  200. /*     Routine is passed a pointer to a buffer containing a copy of the     */
  201. /*     environment strings for the current program.  The procedure is to    */
  202. /*     look through environment strings until two nulls are found in a row. */
  203. /*     Skip the next 2 bytes, and will be pointing to the complete pathname */
  204. /*     of the current program.    Find the last '\' character and the next    */
  205. /*     byte will be the first character of the program name.  Return the    */
  206. /*     address of the start of the file name as a pointer to char.        */
  207. /*                                        */
  208. /*--------------------------------------------------------------------------*/
  209.  
  210. char   *find_name ( buffer )
  211. char   *buffer;
  212. {
  213.    while (1)
  214.        {
  215.        while ( *buffer++ )           /* look for NULL */
  216.        ;
  217.        if ( *buffer == NULL )           /* found one, see if next char is too */
  218.        {
  219.        buffer += 4;            /* if yes, skip to start of pathname */
  220.        break;               /* and get out */
  221.        }
  222.        }
  223.  
  224.    return ( rindex (buffer, '\\') + 1 );
  225.  
  226. }
  227.  
  228.  
  229. /*----- Check to see if we are at the end of mcb chain ---------------------*/
  230. /*                                        */
  231. /*     Look at the first byte in the memory control block. If it is an 'M'  */
  232. /*     then there is another block after it. If it is a 'Z' it is the end   */
  233. /*     of the linked list. Return TRUE if the end is found, else return     */
  234. /*     FALSE.                                    */
  235. /*                                        */
  236. /*--------------------------------------------------------------------------*/
  237.  
  238. bool   check_end ( block )
  239. unsigned   block;
  240. {
  241.    if ( _peek ( 0, block ) == 'M' )
  242.        return ( FALSE );
  243.    else
  244.        return ( TRUE );
  245. }
  246.