/*************************************************************************** * Copyright 1995, Technion, Israel Institute of Technology * Electrical Eng, Software Lab. * Author: Michael Veksler. *************************************************************************** * File: dde_atom.c * Purpose : atom functionality for DDE */ #ifdef CONFIG_IPC #include #include #include #include #include "dde_atom.h" #include "shm_main_blk.h" #include "shm_fragment.h" #include "ldt.h" #include "stddebug.h" #include "debug.h" typedef struct { WORD count; BYTE str[1]; } AtomData, *AtomData_ptr; #define EMPTY 0 /* empty hash entry */ #define DELETED -1 /* deleted hash entry */ #define MIN_STR_ATOM 0xfc00 /* OFS2AtomData_ptr: extract AtomData_ptr from ofs */ #define OFS2AtomData_ptr(ofs) ((AtomData*)((int)&main_block->block+(ofs))) /* OFS2AtomStr: find the string of the atom */ #define OFS2AtomStr(ofs) (OFS2AtomData_ptr(atom_ofs)->str) /* offset of an atom according to index */ #define ATOM_OFS(idx) (main_block->atoms[idx]) /* rot_left: rotate (with wrap-around) */ static __inline__ int rot_left(unsigned var,int count) { return (var<> (sizeof(var)-count)); } /* find the entry in the atom table for this string */ static int FindHash(LPCSTR str) /* ignore str case */ { int i,j; unsigned hash1,hash2; int deleted=-1; /* hash for deleted entry */ int atom_ofs; /* get basic hash parameters */ for (i= hash1= hash2= 0; str[i] ; i++) { hash1= rot_left(hash1,5) ^ toupper(str[i]); hash2= rot_left(hash2,4) ^ toupper(str[i]); } hash1%= DDE_ATOMS; atom_ofs=ATOM_OFS(hash1); switch (atom_ofs) { case EMPTY: /* empty atom entry */ return hash1; case DELETED: /* deleted atom entry */ deleted=hash1; break; default : /* non empty atom entry */ if (lstrcmpi( OFS2AtomStr(atom_ofs) , str) == 0) return hash1; /* found string in atom table */ } hash2%= DDE_ATOMS-1 ; /* hash2=0..(DDE_ATOMS-2) */ hash2++; /* hash2=1..(DDE_ATOMS-1) */ /* make jumps in the hash table by hash2 steps */ for (i=hash1+hash2 ; ; i+=hash2) { /* i wraps around into j */ j=i-DDE_ATOMS; if (j >= 0) i=j; /* i wraps around */ if (i==hash1) /* here if covered all hash locations, and got back to beginning */ return deleted; /* return first empty entry - if any */ atom_ofs=ATOM_OFS(i); switch (atom_ofs) { case EMPTY: /* empty atom entry */ return i; case DELETED: /* deleted atom entry */ if (deleted < 0) /* consider only the first deleted entry */ deleted= i; break; default : /* nonempty atom entry */ if (lstrcmpi( OFS2AtomStr(atom_ofs) , str) == 0) return i; /* found string in atom table */ } } } void ATOM_GlobalInit(void) { int i; for (i=0 ; i < DDE_ATOMS ; i++) ATOM_OFS(i)=EMPTY; } /*********************************************************************** * DDE_GlobalAddAtom */ /* important! don't forget to unlock semaphores before return */ ATOM DDE_GlobalAddAtom( SEGPTR name ) { int atom_idx; int atom_ofs; AtomData_ptr ptr; ATOM atom; char *str; /* First check for integer atom */ if (!HIWORD(name)) return (ATOM)LOWORD(name); str = (char *)PTR_SEG_TO_LIN( name ); if (str[0] == '#') { ATOM atom= (ATOM) atoi(&str[1]); return (atomsem); atom_idx=FindHash(str); atom=(ATOM)0; /* use "return" only at the end so semaphore handling is done only once */ if (atom_idx>=0) { /* unless table full and item not found */ switch (atom_ofs= ATOM_OFS(atom_idx)) { case DELETED: case EMPTY: /* need to allocate new atom */ atom_ofs= shm_FragmentAlloc(&main_block->block, strlen(str)+sizeof(AtomData)); if (atom_ofs==NIL) break; /* no more memory (atom==0) */ ATOM_OFS(atom_idx)=atom_ofs; ptr=OFS2AtomData_ptr(atom_ofs); strcpy(ptr->str,str); ptr->count=1; atom=(ATOM)(atom_idx+MIN_STR_ATOM); break; default : /* has to update existing atom */ OFS2AtomData_ptr(atom_ofs)->count++; atom=(ATOM)(atom_idx+MIN_STR_ATOM); } /* end of switch */ } /* end of if */ shm_write_signal(main_block->sem); return atom; } /*********************************************************************** * DDE_GlobalDeleteAtom */ ATOM DDE_GlobalDeleteAtom( ATOM atom ) { int atom_idx; int atom_ofs; AtomData_ptr atom_ptr; ATOM retval=(ATOM) 0; dprintf_atom(stddeb,"GlobalDeleteAtom(\"%d\")\n",(int)atom); atom_idx=(int)atom - MIN_STR_ATOM; if (atom_idx < 0 ) return 0; DDE_IPC_init(); /* will initialize only if needed */ shm_write_wait(main_block->sem); /* return used only once from here on -- for semaphore simplicity */ switch (atom_ofs=ATOM_OFS(atom_idx)) { case DELETED: case EMPTY: fprintf(stderr,"trying to free unallocated atom %d\n", atom); retval=atom; break; default : atom_ptr=OFS2AtomData_ptr(atom_ofs); if ( --atom_ptr->count == 0) { shm_FragmentFree(&main_block->block,atom_ofs); ATOM_OFS(atom_idx)=DELETED; } } shm_write_signal(main_block->sem); return retval; } /*********************************************************************** * DDE_GlobalFindAtom */ ATOM DDE_GlobalFindAtom( SEGPTR name ) { int atom_idx; int atom_ofs; char *str; dprintf_atom(stddeb,"GlobalFindAtom(%08lx)\n", name ); /* First check for integer atom */ if (!HIWORD(name)) return (ATOM)LOWORD(name); str = (char *)PTR_SEG_TO_LIN( name ); if (str[0] == '#') { ATOM atom= (ATOM) atoi(&str[1]); return (atomsem); atom_idx=FindHash(str); if (atom_idx>=0) atom_ofs=ATOM_OFS(atom_idx); /* is it free ? */ else atom_ofs=EMPTY; shm_read_signal(main_block->sem); if (atom_ofs==EMPTY || atom_ofs==DELETED) return 0; else return (ATOM)(atom_idx+MIN_STR_ATOM); } /*********************************************************************** * DDE_GlobalGetAtomName */ WORD DDE_GlobalGetAtomName( ATOM atom, LPSTR buffer, short count ) { int atom_idx, atom_ofs; int size; /* temporary buffer to hold maximum "#65535\0" */ char str_num[7]; if (count<2) /* no sense to go on */ return 0; atom_idx=(int)atom - MIN_STR_ATOM; if (atom_idx < 0) { /* word atom */ /* use wine convention... */ sprintf(str_num,"#%d%n",(int)atom,&size); if (size+1>count) { /* overflow ? */ /* truncate the string */ size=count-1; str_num[size]='\0'; } strcpy(buffer,str_num); return size; } DDE_IPC_init(); /* will initialize only if needed */ /* string atom */ shm_read_wait(main_block->sem); atom_ofs=ATOM_OFS(atom_idx); if (atom_ofs==EMPTY || atom_ofs==DELETED) { fprintf(stderr,"GlobalGetAtomName: illegal atom=%d\n",(int)atom); size=0; } else { /* non empty entry */ /* string length will be at most count-1, find actual size */ sprintf(buffer,"%.*s%n",count-1, OFS2AtomStr(atom_ofs), &size); } shm_read_signal(main_block->sem); return size; } #endif /* CONFIG_IPC */