Converted to the new debug interface, using script written by Patrik
[wine] / ipc / dde_atom.c
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  */
9 #ifdef CONFIG_IPC
10
11 #include <ctype.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include "dde_atom.h"
15 #include "shm_main_blk.h"
16 #include "shm_fragment.h"
17 #include "ldt.h"
18 #include "debugtools.h"
19
20 DEFAULT_DEBUG_CHANNEL(atom)
21
22 typedef struct
23 {
24         WORD        count;
25         BYTE        str[1];
26 } AtomData, *AtomData_ptr;
27
28 #define EMPTY   0                  /* empty hash entry */
29 #define DELETED -1                 /* deleted hash entry */
30 #define MIN_STR_ATOM 0xfc00
31
32 /* OFS2AtomData_ptr: extract AtomData_ptr from ofs */
33 #define OFS2AtomData_ptr(ofs) ((AtomData*)((int)&main_block->block+(ofs)))
34
35 /* OFS2AtomStr: find the string of the atom */
36 #define OFS2AtomStr(ofs)      (OFS2AtomData_ptr(atom_ofs)->str)
37
38 /* offset of an atom according to index */
39 #define ATOM_OFS(idx) (main_block->atoms[idx])
40
41 /* rot_left: rotate (with wrap-around) */
42 static inline int rot_left(unsigned var,int count)
43 {
44   return (var<<count) | (var>> (sizeof(var)-count));
45 }
46 /* find the entry in the atom table for this string */
47 static int FindHash(LPCSTR str)    /* ignore str case */
48 {
49   int i,j;
50   unsigned hash1,hash2;
51   int deleted=-1;                  /* hash for deleted entry */
52   int atom_ofs;
53
54   /* get basic hash parameters */
55   for (i= hash1= hash2= 0; str[i] ; i++) {
56      hash1= rot_left(hash1,5) ^ toupper(str[i]);
57      hash2= rot_left(hash2,4) ^ toupper(str[i]);
58   }
59
60   hash1%= DDE_ATOMS;
61   atom_ofs=ATOM_OFS(hash1);
62   switch (atom_ofs) {
63     case EMPTY:                    /* empty atom entry */
64       return hash1;                
65     case DELETED:                  /* deleted atom entry */
66       deleted=hash1;
67       break;
68     default :                      /* non empty atom entry */
69       if (lstrcmpi16( OFS2AtomStr(atom_ofs) , str) == 0)
70          return hash1;             /* found string in atom table */
71   }
72   hash2%= DDE_ATOMS-1 ;            /* hash2=0..(DDE_ATOMS-2) */
73   hash2++;                         /* hash2=1..(DDE_ATOMS-1) */
74
75   /* make jumps in the hash table by hash2 steps */
76   for (i=hash1+hash2 ; ; i+=hash2) {
77      /* i wraps around into j */
78      j=i-DDE_ATOMS;
79      if (j >= 0)
80         i=j;                       /* i wraps around */
81      
82      if (i==hash1) 
83         /* here if covered all hash locations, and got back to beginning */
84         return deleted;            /* return first empty entry - if any */
85      atom_ofs=ATOM_OFS(i);
86      switch (atom_ofs) {
87        case EMPTY:                 /* empty atom entry */
88          return i;                 
89        case DELETED:               /* deleted atom entry */
90          if (deleted < 0)
91             /* consider only the first deleted entry */
92             deleted= i;
93          break;
94        default :                   /* nonempty atom entry */
95          if (lstrcmpi16( OFS2AtomStr(atom_ofs) , str) == 0)
96             return i;      /* found string in atom table */
97      }
98   }
99 }
100
101 void ATOM_GlobalInit(void)
102 {
103   int i;
104   
105   for (i=0 ; i < DDE_ATOMS ; i++)
106      ATOM_OFS(i)=EMPTY;
107 }
108
109 /***********************************************************************
110  *           DDE_GlobalAddAtom
111  */
112
113 /* important! don't forget to unlock semaphores before return */
114 ATOM DDE_GlobalAddAtom( SEGPTR name )
115 {
116   int atom_idx;
117   int atom_ofs;
118   AtomData_ptr ptr;
119   ATOM atom;
120   char *str;
121
122   /* First check for integer atom */
123
124   if (!HIWORD(name)) return (ATOM)LOWORD(name);
125
126   str = (char *)PTR_SEG_TO_LIN( name );
127   if (str[0] == '#')
128   {
129      ATOM atom= (ATOM) atoi(&str[1]);
130      return (atom<MIN_STR_ATOM) ? atom : 0;
131   }
132
133   TRACE("(\"%s\")\n",str);
134
135   DDE_IPC_init();               /* will initialize only if needed */
136   
137   shm_write_wait(main_block->sem);
138
139   atom_idx=FindHash(str);
140   atom=(ATOM)0;
141
142   /* use "return" only at the end so semaphore handling is done only once */
143   if (atom_idx>=0) {
144      /* unless table full and item not found */
145      switch (atom_ofs= ATOM_OFS(atom_idx)) {
146        case DELETED:
147        case EMPTY:                 /* need to allocate new atom */
148          atom_ofs= shm_FragmentAlloc(&main_block->block,
149                                      strlen(str)+sizeof(AtomData));
150          if (atom_ofs==NIL)
151             break;                 /* no more memory (atom==0) */
152          ATOM_OFS(atom_idx)=atom_ofs;
153          ptr=OFS2AtomData_ptr(atom_ofs);
154          strcpy(ptr->str,str);
155          ptr->count=1;
156          atom=(ATOM)(atom_idx+MIN_STR_ATOM);
157          break;
158        default :                   /* has to update existing atom */
159          OFS2AtomData_ptr(atom_ofs)->count++;
160          atom=(ATOM)(atom_idx+MIN_STR_ATOM);
161      } /* end of switch */
162   } /* end of if */
163   shm_write_signal(main_block->sem);
164   return atom;
165 }
166
167 /***********************************************************************
168  *           DDE_GlobalDeleteAtom
169  */
170
171 ATOM DDE_GlobalDeleteAtom( ATOM atom )
172 {
173   int atom_idx;
174   int atom_ofs;
175   AtomData_ptr atom_ptr;
176   ATOM retval=(ATOM) 0;
177   
178   TRACE("(\"%d\")\n",(int)atom);
179   atom_idx=(int)atom - MIN_STR_ATOM;
180   
181   if (atom_idx < 0 )
182      return 0;
183
184   DDE_IPC_init();          /* will initialize only if needed */
185
186   shm_write_wait(main_block->sem);
187   /* return used only once from here on -- for semaphore simplicity */
188   switch (atom_ofs=ATOM_OFS(atom_idx)) {
189     case DELETED:
190     case EMPTY:
191       WARN("Trying to free unallocated atom %d\n", atom);
192       retval=atom;
193       break;
194     default :
195       atom_ptr=OFS2AtomData_ptr(atom_ofs);
196       if ( --atom_ptr->count == 0) {
197          shm_FragmentFree(&main_block->block,atom_ofs);
198          ATOM_OFS(atom_idx)=DELETED;
199       }
200   }
201   
202   shm_write_signal(main_block->sem);
203   return retval;
204 }
205
206 /***********************************************************************
207  *           DDE_GlobalFindAtom
208  */
209 ATOM DDE_GlobalFindAtom( SEGPTR name )
210 {
211   int atom_idx;
212   int atom_ofs;
213   char *str;
214
215   TRACE("(%08lx)\n", name );
216
217   /* First check for integer atom */
218
219   if (!HIWORD(name)) return (ATOM)LOWORD(name);
220
221   str = (char *)PTR_SEG_TO_LIN( name );
222   if (str[0] == '#')
223   {
224      ATOM atom= (ATOM) atoi(&str[1]);
225      return (atom<MIN_STR_ATOM) ? atom : 0;
226   }
227   TRACE("(\"%s\")\n",str);
228
229   DDE_IPC_init();               /* will initialize only if needed */
230
231   shm_read_wait(main_block->sem);
232   atom_idx=FindHash(str);
233   if (atom_idx>=0)                 
234      atom_ofs=ATOM_OFS(atom_idx);  /* is it free ? */
235   else
236      atom_ofs=EMPTY;
237   shm_read_signal(main_block->sem);
238
239   if (atom_ofs==EMPTY || atom_ofs==DELETED)
240      return 0;
241   else
242      return (ATOM)(atom_idx+MIN_STR_ATOM);
243 }
244
245 /***********************************************************************
246  *           DDE_GlobalGetAtomName
247  */
248 WORD DDE_GlobalGetAtomName( ATOM atom, LPSTR buffer, short count )
249 {
250   int atom_idx, atom_ofs;
251   int size;
252   /* temporary buffer to hold maximum "#65535\0" */
253   char str_num[7];
254   
255   if (count<2)                     /* no sense to go on */
256      return 0;
257   atom_idx=(int)atom - MIN_STR_ATOM;
258   
259   if (atom_idx < 0) {              /* word atom */
260      /* use wine convention... */
261      sprintf(str_num,"#%d%n",(int)atom,&size);
262      if (size+1>count) {           /* overflow ? */
263         /* truncate the string */
264         size=count-1;
265         str_num[size]='\0';
266      }
267      strcpy(buffer,str_num);
268      return size;
269   }
270
271   DDE_IPC_init();               /* will initialize only if needed */
272
273   /* string atom */
274   shm_read_wait(main_block->sem);
275   atom_ofs=ATOM_OFS(atom_idx);
276   if (atom_ofs==EMPTY || atom_ofs==DELETED) {
277      WARN("Illegal atom=%d\n",(int)atom);
278      size=0;
279   } else {                         /* non empty entry */
280      /* string length will be at most count-1, find actual size */
281      sprintf(buffer,"%.*s%n",count-1, OFS2AtomStr(atom_ofs), &size);
282   }
283   shm_read_signal(main_block->sem);
284   return size;
285 }
286
287 #endif  /* CONFIG_IPC */