| /*************************************************************************** | |
| * 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 <ctype.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include "dde_atom.h" | |
| #include "shm_main_blk.h" | |
| #include "shm_fragment.h" | |
| #include "ldt.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<<count) | (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 (lstrcmpi16( 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 (lstrcmpi16( 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 (atom<MIN_STR_ATOM) ? atom : 0; | |
| } | |
| TRACE(atom,"(\"%s\")\n",str); | |
| DDE_IPC_init(); /* will initialize only if needed */ | |
| shm_write_wait(main_block->sem); | |
| 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; | |
| TRACE(atom,"(\"%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: | |
| WARN(atom, "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; | |
| TRACE(atom,"(%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 (atom<MIN_STR_ATOM) ? atom : 0; | |
| } | |
| TRACE(atom,"(\"%s\")\n",str); | |
| DDE_IPC_init(); /* will initialize only if needed */ | |
| shm_read_wait(main_block->sem); | |
| 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) { | |
| WARN(atom,"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 */ |