Input SDL plugin. Compile and run on the OpenPandora. Include config for Pandora...
[mupen64plus-pandora.git] / source / mupen64plus-input-sdl / src / autoconfig.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus-input-sdl - autoconfig.c                                  *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2009-2013 Richard Goedeken                              *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include <string.h>
23
24 #include "m64p_types.h"
25 #include "m64p_config.h"
26 #include "osal_preproc.h"
27 #include "autoconfig.h"
28 #include "plugin.h"
29
30 /* local definitions */
31 #define INI_FILE_NAME "InputAutoCfg.ini"
32 typedef struct {
33     m64p_handle pSrc;
34     m64p_handle pDst;
35 } SCopySection;
36
37 /* local functions */
38 static char *StripSpace(char *pIn)
39 {
40     char *pEnd = pIn + strlen(pIn) - 1;
41
42     while (*pIn == ' ' || *pIn == '\t' || *pIn == '\r' || *pIn == '\n')
43         pIn++;
44
45     while (pIn <= pEnd && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\r' || *pEnd == '\n'))
46         *pEnd-- = 0;
47
48     return pIn;
49 }
50
51 static void CopyParamCallback(void * context, const char *ParamName, m64p_type ParamType)
52 {
53     SCopySection *pCpyContext = (SCopySection *) context;
54     int paramInt;
55     float paramFloat;
56     char paramString[1024];
57
58     // handle the parameter copy depending upon type
59     switch (ParamType)
60     {
61         case M64TYPE_INT:
62         case M64TYPE_BOOL:
63             if (ConfigGetParameter(pCpyContext->pSrc, ParamName, ParamType, &paramInt, sizeof(int)) == M64ERR_SUCCESS)
64                 ConfigSetParameter(pCpyContext->pDst, ParamName, ParamType, &paramInt);
65             break;
66         case M64TYPE_FLOAT:
67             if (ConfigGetParameter(pCpyContext->pSrc, ParamName, ParamType, &paramFloat, sizeof(float)) == M64ERR_SUCCESS)
68                 ConfigSetParameter(pCpyContext->pDst, ParamName, ParamType, &paramFloat);
69             break;
70         case M64TYPE_STRING:
71             if (ConfigGetParameter(pCpyContext->pSrc, ParamName, ParamType, paramString, 1024) == M64ERR_SUCCESS)
72                 ConfigSetParameter(pCpyContext->pDst, ParamName, ParamType, paramString);
73             break;
74         default:
75             // this should never happen
76             DebugMessage(M64MSG_ERROR, "Unknown source parameter type %i in copy callback", (int) ParamType);
77             return;
78     }
79 }
80
81 /* global functions */
82 int auto_copy_inputconfig(const char *pccSourceSectionName, const char *pccDestSectionName, const char *sdlJoyName)
83 {
84     SCopySection cpyContext;
85
86     if (ConfigOpenSection(pccSourceSectionName, &cpyContext.pSrc) != M64ERR_SUCCESS)
87     {
88         DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: Couldn't open source config section '%s' for copying", pccSourceSectionName);
89         return 0;
90     }
91
92     if (ConfigOpenSection(pccDestSectionName, &cpyContext.pDst) != M64ERR_SUCCESS)
93     {
94         DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: Couldn't open destination config section '%s' for copying", pccDestSectionName);
95         return 0;
96     }
97
98     // set the 'name' parameter
99     if (sdlJoyName != NULL)
100     {
101         if (ConfigSetParameter(cpyContext.pDst, "name", M64TYPE_STRING, sdlJoyName) != M64ERR_SUCCESS)
102         {
103             DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: Couldn't set 'name' parameter to '%s' in section '%s'", sdlJoyName, pccDestSectionName);
104             return 0;
105         }
106     }
107
108     // the copy gets done by the callback function
109     if (ConfigListParameters(cpyContext.pSrc, (void *) &cpyContext, CopyParamCallback) != M64ERR_SUCCESS)
110     {
111         DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: parameter list copy failed");
112         return 0;
113     }
114
115     return 1;
116 }
117
118 int auto_set_defaults(int iDeviceIdx, const char *joySDLName)
119 {
120     FILE *pfIn;
121     m64p_handle pConfig = NULL;
122     const char *CfgFilePath = ConfigGetSharedDataFilepath(INI_FILE_NAME);
123     enum { E_NAME_SEARCH, E_NAME_FOUND, E_PARAM_READ } eParseState;
124     char *pchIni, *pchNextLine, *pchCurLine;
125     long iniLength;
126     int ControllersFound = 0;
127
128     /* if we couldn't get a name (no joystick plugged in to given port), then return with a failure */
129     if (joySDLName == NULL)
130         return 0;
131     /* if we couldn't find the shared data file, dump an error and return */
132     if (CfgFilePath == NULL || strlen(CfgFilePath) < 1)
133     {
134         DebugMessage(M64MSG_ERROR, "Couldn't find config file '%s'", INI_FILE_NAME);
135         return 0;
136     }
137
138     /* read the input auto-config .ini file */
139     pfIn = fopen(CfgFilePath, "rb");
140     if (pfIn == NULL)
141     {
142         DebugMessage(M64MSG_ERROR, "Couldn't open config file '%s'", CfgFilePath);
143         return 0;
144     }
145     fseek(pfIn, 0L, SEEK_END);
146     iniLength = ftell(pfIn);
147     fseek(pfIn, 0L, SEEK_SET);
148     pchIni = (char *) malloc(iniLength + 1);
149     if (pchIni == NULL)
150     {
151         DebugMessage(M64MSG_ERROR, "Couldn't allocate %li bytes for config file '%s'", iniLength, CfgFilePath);
152         fclose(pfIn);
153         return 0;
154     }
155     if (fread(pchIni, 1, iniLength, pfIn) != iniLength)
156     {
157         DebugMessage(M64MSG_ERROR, "File read failed for %li bytes of config file '%s'", iniLength, CfgFilePath);
158         free(pchIni);
159         fclose(pfIn);
160         return 0;
161     }
162     fclose(pfIn);
163     pchIni[iniLength] = 0;
164
165     /* parse the INI file, line by line */
166     pchNextLine = pchIni;
167     eParseState = E_NAME_SEARCH;
168     while (pchNextLine != NULL && *pchNextLine != 0)
169     {
170         char *pivot = NULL;
171         /* set up character pointers */
172         pchCurLine = pchNextLine;
173         pchNextLine = strchr(pchNextLine, '\n');
174         if (pchNextLine != NULL)
175             *pchNextLine++ = 0;
176         pchCurLine = StripSpace(pchCurLine);
177
178         /* handle blank/comment lines */
179         if (strlen(pchCurLine) < 1 || *pchCurLine == ';' || *pchCurLine == '#')
180             continue;
181
182         /* handle section (joystick name in ini file) */
183         if (*pchCurLine == '[' && pchCurLine[strlen(pchCurLine)-1] == ']')
184         {
185             char Word[64];
186             char *wordPtr;
187             int  joyFound = 1;
188
189             if (eParseState == E_PARAM_READ)
190             {
191                 /* we've finished parsing all parameters for the discovered input device */
192                 free(pchIni);
193                 return ControllersFound;
194             }
195             else if (eParseState == E_NAME_FOUND)
196             {
197                 /* this is an equivalent device name to the one we're looking for (and found); keep looking for parameters */
198                 continue;
199             }
200             /* we need to look through the device name word by word to see if it matches the joySDLName that we're looking for */ 
201             pchCurLine[strlen(pchCurLine)-1] = 0;
202             wordPtr = StripSpace(pchCurLine + 1);
203             /* first, if there is a preceding system name in this .ini device name, and the system matches, then strip out */
204 #if defined(__unix__)
205             if (strncmp(wordPtr, "Unix:", 5) == 0)
206                 wordPtr = StripSpace(wordPtr + 5);
207 #endif
208 #if defined(__linux__)
209             if (strncmp(wordPtr, "Linux:", 6) == 0)
210                 wordPtr = StripSpace(wordPtr + 6);
211 #endif
212 #if defined(__APPLE__)
213             if (strncmp(wordPtr, "OSX:", 4) == 0)
214                 wordPtr = StripSpace(wordPtr + 4);
215 #endif
216 #if defined(WIN32)
217             if (strncmp(wordPtr, "Win32:", 6) == 0)
218                 wordPtr = StripSpace(wordPtr + 6);
219 #endif
220             /* search in the .ini device name for all the words in the joystick name.  If any are missing, then this is not the right joystick model */
221             while (wordPtr != NULL && strlen(wordPtr) > 0)
222             {
223                 char *nextSpace = strchr(wordPtr, ' ');
224                 if (nextSpace == NULL)
225                 {
226                     strncpy(Word, wordPtr, 63);
227                     Word[63] = 0;
228                     wordPtr = NULL;
229                 }
230                 else
231                 {
232                     int length = (int) (nextSpace - wordPtr);
233                     if (length > 63) length = 63;
234                     strncpy(Word, wordPtr, length);
235                     Word[length] = 0;
236                     wordPtr = nextSpace + 1;
237                 }
238                 if (strcasestr(joySDLName, Word) == NULL)
239                     joyFound = 0;
240             }
241             /* if we found the right joystick, then open up the core config section to store parameters and set the 'device' param */
242             if (joyFound)
243             {
244                 char SectionName[32];
245                 sprintf(SectionName, "AutoConfig%i", ControllersFound);
246                 if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
247                 {
248                     DebugMessage(M64MSG_ERROR, "auto_set_defaults(): Couldn't open config section '%s'", SectionName);
249                     free(pchIni);
250                     return 0;
251                 }
252                 eParseState = E_NAME_FOUND;
253                 ControllersFound++;
254                 ConfigSetParameter(pConfig, "device", M64TYPE_INT, &iDeviceIdx);
255             }
256             continue;
257         }
258
259         /* handle parameters */
260         pivot = strchr(pchCurLine, '=');
261         if (pivot != NULL)
262         {
263             /* if we haven't found the correct section yet, just skip this */
264             if (eParseState == E_NAME_SEARCH)
265                 continue;
266             eParseState = E_PARAM_READ;
267             /* otherwise, store this parameter in the current active joystick config */
268             *pivot++ = 0;
269             pchCurLine = StripSpace(pchCurLine);
270             pivot = StripSpace(pivot);
271             if (strcasecmp(pchCurLine, "plugin") == 0 || strcasecmp(pchCurLine, "device") == 0)
272             {
273                 int iVal = atoi(pivot);
274                 ConfigSetParameter(pConfig, pchCurLine, M64TYPE_INT, &iVal);
275             }
276             else if (strcasecmp(pchCurLine, "plugged") == 0 || strcasecmp(pchCurLine, "mouse") == 0)
277             {
278                 int bVal = (strcasecmp(pivot, "true") == 0);
279                 ConfigSetParameter(pConfig, pchCurLine, M64TYPE_BOOL, &bVal);
280             }
281             else
282             {
283                 ConfigSetParameter(pConfig, pchCurLine, M64TYPE_STRING, pivot);
284             }
285             continue;
286         }
287
288         /* handle keywords */
289         if (pchCurLine[strlen(pchCurLine)-1] == ':')
290         {
291             /* if we haven't found the correct section yet, just skip this */
292             if (eParseState == E_NAME_SEARCH)
293                 continue;
294             /* otherwise parse the keyword */
295             if (strcmp(pchCurLine, "__NextController:") == 0)
296             {
297                 char SectionName[32];
298                 /* if there are no more N64 controller spaces left, then exit */
299                 if (ControllersFound == 4)
300                 {
301                     free(pchIni);
302                     return ControllersFound;
303                 }
304                 /* otherwise go to the next N64 controller */
305                 sprintf(SectionName, "AutoConfig%i", ControllersFound);
306                 if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
307                 {
308                     DebugMessage(M64MSG_ERROR, "auto_set_defaults(): Couldn't open config section '%s'", SectionName);
309                     free(pchIni);
310                     return ControllersFound;
311                 }
312                 ControllersFound++;
313                 ConfigSetParameter(pConfig, "device", M64TYPE_INT, &iDeviceIdx);
314             }
315             else
316             {
317                 DebugMessage(M64MSG_ERROR, "Unknown keyword '%s' in %s", pchCurLine, INI_FILE_NAME);
318             }
319             continue;
320         }
321
322         /* unhandled line in .ini file */
323         DebugMessage(M64MSG_ERROR, "Invalid line in %s: '%s'", INI_FILE_NAME, pchCurLine);
324     }
325
326     if (eParseState == E_PARAM_READ)
327     {
328         /* we've finished parsing all parameters for the discovered input device, which is the last in the .ini file */
329         free(pchIni);
330         return ControllersFound;
331     }
332
333     free(pchIni);
334     return 0;
335 }
336
337