Release 950727
[wine/multimedia.git] / ipc / dde_atom.c
blobc6ca2aa5b01c418eccc57732780e331f2e5b015d
1 /***************************************************************************
2 * Copyright 1995, Technion, Israel Institute of Technology
3 * Electrical Eng, Software Lab.
4 * Author: Michael Veksler.
5 ***************************************************************************
6 * File: dde_atom.c
7 * Purpose : atom functionality for DDE
8 */
10 #include <ctype.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include "dde_atom.h"
15 #include "shm_main_blk.h"
16 #include "shm_fragment.h"
17 #include "stddebug.h"
18 #include "debug.h"
20 typedef struct
22 WORD count;
23 BYTE str[1];
24 } AtomData, *AtomData_ptr;
26 #define EMPTY 0 /* empty hash entry */
27 #define DELETED -1 /* deleted hash entry */
28 #define MIN_STR_ATOM 0xfc00
30 /* OFS2AtomData_ptr: extract AtomData_ptr from ofs */
31 #define OFS2AtomData_ptr(ofs) ((AtomData*)((int)&main_block->block+(ofs)))
33 /* OFS2AtomStr: find the string of the atom */
34 #define OFS2AtomStr(ofs) (OFS2AtomData_ptr(atom_ofs)->str)
36 /* offset of an atom according to index */
37 #define ATOM_OFS(idx) (main_block->atoms[idx])
39 /* rot_left: rotate (with wrap-around) */
40 static __inline__ int rot_left(unsigned var,int count)
42 return (var<<count) | (var>> (sizeof(var)-count));
44 /* find the entry in the atom table for this string */
45 static int FindHash(LPCSTR str) /* ignore str case */
47 int i,j;
48 unsigned hash1,hash2;
49 int deleted=-1; /* hash for deleted entry */
50 int atom_ofs;
52 /* get basic hash parameters */
53 for (i= hash1= hash2= 0; str[i] ; i++) {
54 hash1= rot_left(hash1,5) ^ toupper(str[i]);
55 hash2= rot_left(hash2,4) ^ toupper(str[i]);
58 hash1%= DDE_ATOMS;
59 atom_ofs=ATOM_OFS(hash1);
60 switch (atom_ofs) {
61 case EMPTY: /* empty atom entry */
62 return hash1;
63 case DELETED: /* deleted atom entry */
64 deleted=hash1;
65 break;
66 default : /* non empty atom entry */
67 if ( strcasecmp( OFS2AtomStr(atom_ofs) , str) == 0)
68 return hash1; /* found string in atom table */
70 hash2%= DDE_ATOMS-1 ; /* hash2=0..(DDE_ATOMS-2) */
71 hash2++; /* hash2=1..(DDE_ATOMS-1) */
73 /* make jumps in the hash table by hash2 steps */
74 for (i=hash1+hash2 ; ; i+=hash2) {
75 /* i wraps around into j */
76 j=i-DDE_ATOMS;
77 if (j >= 0)
78 i=j; /* i wraps around */
80 if (i==hash1)
81 /* here if covered all hash locations, and got back to beginning */
82 return deleted; /* return first empty entry - if any */
83 atom_ofs=ATOM_OFS(i);
84 switch (atom_ofs) {
85 case EMPTY: /* empty atom entry */
86 return i;
87 case DELETED: /* deleted atom entry */
88 if (deleted < 0)
89 /* consider only the first deleted entry */
90 deleted= i;
91 break;
92 default : /* nonempty atom entry */
93 if ( strcasecmp( OFS2AtomStr(atom_ofs) , str) == 0)
94 return i; /* found string in atom table */
99 void ATOM_GlobalInit(void)
101 int i;
103 for (i=0 ; i < DDE_ATOMS ; i++)
104 ATOM_OFS(i)=EMPTY;
107 /***********************************************************************
108 * GlobalAddAtom (USER.268)
111 /* important! don't forget to unlock semaphores before return */
112 ATOM GlobalAddAtom( LPCSTR str )
114 int atom_idx;
115 int atom_ofs;
116 AtomData_ptr ptr;
117 ATOM atom;
119 dprintf_atom(stddeb,"GlobalAddAtom(%p)\n", str);
120 if ((unsigned) str < MIN_STR_ATOM) /* MS-windows convention */
121 return (ATOM) (unsigned) str;
122 if (str[0] == '#') { /* wine convention */
123 atom= (ATOM) atoi(&str[1]);
124 return (atom<MIN_STR_ATOM) ? atom : 0;
126 dprintf_atom(stddeb,"GlobalAddAtom(\"%s\")\n",str);
128 DDE_IPC_init(); /* will initialize only if needed */
130 shm_write_wait(main_block->sem);
132 atom_idx=FindHash(str);
133 atom=(ATOM)0;
135 /* use "return" only at the end so semaphore handling is done only once */
136 if (atom_idx>=0) {
137 /* unless table full and item not found */
138 switch (atom_ofs= ATOM_OFS(atom_idx)) {
139 case DELETED:
140 case EMPTY: /* need to allocate new atom */
141 atom_ofs= shm_FragmentAlloc(&main_block->block,
142 strlen(str)+sizeof(AtomData));
143 if (atom_ofs==NIL)
144 break; /* no more memory (atom==0) */
145 ATOM_OFS(atom_idx)=atom_ofs;
146 ptr=OFS2AtomData_ptr(atom_ofs);
147 strcpy(ptr->str,str);
148 ptr->count=1;
149 atom=(ATOM)(atom_idx+MIN_STR_ATOM);
150 break;
151 default : /* has to update existing atom */
152 OFS2AtomData_ptr(atom_ofs)->count++;
153 atom=(ATOM)(atom_idx+MIN_STR_ATOM);
154 } /* end of switch */
155 } /* end of if */
156 shm_write_signal(main_block->sem);
157 return atom;
160 /***********************************************************************
161 * GlobalDeleteAtom (USER.269)
164 ATOM GlobalDeleteAtom( ATOM atom )
166 int atom_idx;
167 int atom_ofs;
168 AtomData_ptr atom_ptr;
169 ATOM retval=(ATOM) 0;
171 dprintf_atom(stddeb,"GlobalDeleteAtom(\"%d\")\n",(int)atom);
172 atom_idx=(int)atom - MIN_STR_ATOM;
174 if (atom_idx < 0 )
175 return 0;
177 DDE_IPC_init(); /* will initialize only if needed */
179 shm_write_wait(main_block->sem);
180 /* return used only once from here on -- for semaphore simplicity */
181 switch (atom_ofs=ATOM_OFS(atom_idx)) {
182 case DELETED:
183 case EMPTY:
184 fprintf(stderr,"trying to free unallocated atom %d\n", atom);
185 retval=atom;
186 break;
187 default :
188 atom_ptr=OFS2AtomData_ptr(atom_ofs);
189 if ( --atom_ptr->count == 0) {
190 shm_FragmentFree(&main_block->block,atom_ofs);
191 ATOM_OFS(atom_idx)=DELETED;
195 shm_write_signal(main_block->sem);
196 return retval;
199 /***********************************************************************
200 * GlobalFindAtom (USER.270)
202 ATOM GlobalFindAtom( LPCSTR str )
204 int atom_idx;
205 int atom_ofs;
207 dprintf_atom(stddeb,"GlobalFindAtom(%p)\n", str );
208 if ((unsigned) str < MIN_STR_ATOM) /* MS-windows convention */
209 return (ATOM) (unsigned) str;
210 if (str[0] == '#') { /* wine convention */
211 ATOM atom= (ATOM) atoi(&str[1]);
212 return (atom<MIN_STR_ATOM) ? atom : 0;
214 dprintf_atom(stddeb,"GlobalFindAtom(\"%s\")\n",str);
216 DDE_IPC_init(); /* will initialize only if needed */
218 shm_read_wait(main_block->sem);
219 atom_idx=FindHash(str);
220 if (atom_idx>=0)
221 atom_ofs=ATOM_OFS(atom_idx); /* is it free ? */
222 else
223 atom_ofs=EMPTY;
224 shm_read_signal(main_block->sem);
226 if (atom_ofs==EMPTY || atom_ofs==DELETED)
227 return 0;
228 else
229 return (ATOM)(atom_idx+MIN_STR_ATOM);
232 /***********************************************************************
233 * GlobalGetAtomName (USER.271)
235 WORD GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
237 int atom_idx, atom_ofs;
238 int size;
239 /* temporary buffer to hold maximum "#65535\0" */
240 char str_num[7];
242 if (count<2) /* no sense to go on */
243 return 0;
244 atom_idx=(int)atom - MIN_STR_ATOM;
246 if (atom_idx < 0) { /* word atom */
247 /* use wine convention... */
248 sprintf(str_num,"#%d%n",(int)atom,&size);
249 if (size+1>count) { /* overflow ? */
250 /* truncate the string */
251 size=count-1;
252 str_num[size]='\0';
254 strcpy(buffer,str_num);
255 return size;
258 DDE_IPC_init(); /* will initialize only if needed */
260 /* string atom */
261 shm_read_wait(main_block->sem);
262 atom_ofs=ATOM_OFS(atom_idx);
263 if (atom_ofs==EMPTY || atom_ofs==DELETED) {
264 fprintf(stderr,"GlobalGetAtomName: illegal atom=%d\n",(int)atom);
265 size=0;
266 } else { /* non empty entry */
267 /* string length will be at most count-1, find actual size */
268 sprintf(buffer,"%.*s%n",count-1, OFS2AtomStr(atom_ofs), &size);
270 shm_read_signal(main_block->sem);
271 return size;