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