1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus-input-sdl - autoconfig.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2009-2013 Richard Goedeken *
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. *
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. *
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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 #include "m64p_types.h"
25 #include "m64p_config.h"
26 #include "osal_preproc.h"
27 #include "autoconfig.h"
30 /* local definitions */
31 #define INI_FILE_NAME "InputAutoCfg.ini"
38 static char *StripSpace(char *pIn)
40 char *pEnd = pIn + strlen(pIn) - 1;
42 while (*pIn == ' ' || *pIn == '\t' || *pIn == '\r' || *pIn == '\n')
45 while (pIn <= pEnd && (*pEnd == ' ' || *pEnd == '\t' || *pEnd == '\r' || *pEnd == '\n'))
51 static void CopyParamCallback(void * context, const char *ParamName, m64p_type ParamType)
53 SCopySection *pCpyContext = (SCopySection *) context;
56 char paramString[1024];
58 // handle the parameter copy depending upon type
63 if (ConfigGetParameter(pCpyContext->pSrc, ParamName, ParamType, ¶mInt, sizeof(int)) == M64ERR_SUCCESS)
64 ConfigSetParameter(pCpyContext->pDst, ParamName, ParamType, ¶mInt);
67 if (ConfigGetParameter(pCpyContext->pSrc, ParamName, ParamType, ¶mFloat, sizeof(float)) == M64ERR_SUCCESS)
68 ConfigSetParameter(pCpyContext->pDst, ParamName, ParamType, ¶mFloat);
71 if (ConfigGetParameter(pCpyContext->pSrc, ParamName, ParamType, paramString, 1024) == M64ERR_SUCCESS)
72 ConfigSetParameter(pCpyContext->pDst, ParamName, ParamType, paramString);
75 // this should never happen
76 DebugMessage(M64MSG_ERROR, "Unknown source parameter type %i in copy callback", (int) ParamType);
81 /* global functions */
82 int auto_copy_inputconfig(const char *pccSourceSectionName, const char *pccDestSectionName, const char *sdlJoyName)
84 SCopySection cpyContext;
86 if (ConfigOpenSection(pccSourceSectionName, &cpyContext.pSrc) != M64ERR_SUCCESS)
88 DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: Couldn't open source config section '%s' for copying", pccSourceSectionName);
92 if (ConfigOpenSection(pccDestSectionName, &cpyContext.pDst) != M64ERR_SUCCESS)
94 DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: Couldn't open destination config section '%s' for copying", pccDestSectionName);
98 // set the 'name' parameter
99 if (sdlJoyName != NULL)
101 if (ConfigSetParameter(cpyContext.pDst, "name", M64TYPE_STRING, sdlJoyName) != M64ERR_SUCCESS)
103 DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: Couldn't set 'name' parameter to '%s' in section '%s'", sdlJoyName, pccDestSectionName);
108 // the copy gets done by the callback function
109 if (ConfigListParameters(cpyContext.pSrc, (void *) &cpyContext, CopyParamCallback) != M64ERR_SUCCESS)
111 DebugMessage(M64MSG_ERROR, "auto_copy_inputconfig: parameter list copy failed");
118 int auto_set_defaults(int iDeviceIdx, const char *joySDLName)
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;
126 int ControllersFound = 0;
128 /* if we couldn't get a name (no joystick plugged in to given port), then return with a failure */
129 if (joySDLName == NULL)
131 /* if we couldn't find the shared data file, dump an error and return */
132 if (CfgFilePath == NULL || strlen(CfgFilePath) < 1)
134 DebugMessage(M64MSG_ERROR, "Couldn't find config file '%s'", INI_FILE_NAME);
138 /* read the input auto-config .ini file */
139 pfIn = fopen(CfgFilePath, "rb");
142 DebugMessage(M64MSG_ERROR, "Couldn't open config file '%s'", CfgFilePath);
145 fseek(pfIn, 0L, SEEK_END);
146 iniLength = ftell(pfIn);
147 fseek(pfIn, 0L, SEEK_SET);
148 pchIni = (char *) malloc(iniLength + 1);
151 DebugMessage(M64MSG_ERROR, "Couldn't allocate %li bytes for config file '%s'", iniLength, CfgFilePath);
155 if (fread(pchIni, 1, iniLength, pfIn) != iniLength)
157 DebugMessage(M64MSG_ERROR, "File read failed for %li bytes of config file '%s'", iniLength, CfgFilePath);
163 pchIni[iniLength] = 0;
165 /* parse the INI file, line by line */
166 pchNextLine = pchIni;
167 eParseState = E_NAME_SEARCH;
168 while (pchNextLine != NULL && *pchNextLine != 0)
171 /* set up character pointers */
172 pchCurLine = pchNextLine;
173 pchNextLine = strchr(pchNextLine, '\n');
174 if (pchNextLine != NULL)
176 pchCurLine = StripSpace(pchCurLine);
178 /* handle blank/comment lines */
179 if (strlen(pchCurLine) < 1 || *pchCurLine == ';' || *pchCurLine == '#')
182 /* handle section (joystick name in ini file) */
183 if (*pchCurLine == '[' && pchCurLine[strlen(pchCurLine)-1] == ']')
189 if (eParseState == E_PARAM_READ)
191 /* we've finished parsing all parameters for the discovered input device */
193 return ControllersFound;
195 else if (eParseState == E_NAME_FOUND)
197 /* this is an equivalent device name to the one we're looking for (and found); keep looking for parameters */
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);
208 #if defined(__linux__)
209 if (strncmp(wordPtr, "Linux:", 6) == 0)
210 wordPtr = StripSpace(wordPtr + 6);
212 #if defined(__APPLE__)
213 if (strncmp(wordPtr, "OSX:", 4) == 0)
214 wordPtr = StripSpace(wordPtr + 4);
217 if (strncmp(wordPtr, "Win32:", 6) == 0)
218 wordPtr = StripSpace(wordPtr + 6);
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)
223 char *nextSpace = strchr(wordPtr, ' ');
224 if (nextSpace == NULL)
226 strncpy(Word, wordPtr, 63);
232 int length = (int) (nextSpace - wordPtr);
233 if (length > 63) length = 63;
234 strncpy(Word, wordPtr, length);
236 wordPtr = nextSpace + 1;
238 if (strcasestr(joySDLName, Word) == NULL)
241 /* if we found the right joystick, then open up the core config section to store parameters and set the 'device' param */
244 char SectionName[32];
245 sprintf(SectionName, "AutoConfig%i", ControllersFound);
246 if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
248 DebugMessage(M64MSG_ERROR, "auto_set_defaults(): Couldn't open config section '%s'", SectionName);
252 eParseState = E_NAME_FOUND;
254 ConfigSetParameter(pConfig, "device", M64TYPE_INT, &iDeviceIdx);
259 /* handle parameters */
260 pivot = strchr(pchCurLine, '=');
263 /* if we haven't found the correct section yet, just skip this */
264 if (eParseState == E_NAME_SEARCH)
266 eParseState = E_PARAM_READ;
267 /* otherwise, store this parameter in the current active joystick config */
269 pchCurLine = StripSpace(pchCurLine);
270 pivot = StripSpace(pivot);
271 if (strcasecmp(pchCurLine, "plugin") == 0 || strcasecmp(pchCurLine, "device") == 0)
273 int iVal = atoi(pivot);
274 ConfigSetParameter(pConfig, pchCurLine, M64TYPE_INT, &iVal);
276 else if (strcasecmp(pchCurLine, "plugged") == 0 || strcasecmp(pchCurLine, "mouse") == 0)
278 int bVal = (strcasecmp(pivot, "true") == 0);
279 ConfigSetParameter(pConfig, pchCurLine, M64TYPE_BOOL, &bVal);
283 ConfigSetParameter(pConfig, pchCurLine, M64TYPE_STRING, pivot);
288 /* handle keywords */
289 if (pchCurLine[strlen(pchCurLine)-1] == ':')
291 /* if we haven't found the correct section yet, just skip this */
292 if (eParseState == E_NAME_SEARCH)
294 /* otherwise parse the keyword */
295 if (strcmp(pchCurLine, "__NextController:") == 0)
297 char SectionName[32];
298 /* if there are no more N64 controller spaces left, then exit */
299 if (ControllersFound == 4)
302 return ControllersFound;
304 /* otherwise go to the next N64 controller */
305 sprintf(SectionName, "AutoConfig%i", ControllersFound);
306 if (ConfigOpenSection(SectionName, &pConfig) != M64ERR_SUCCESS)
308 DebugMessage(M64MSG_ERROR, "auto_set_defaults(): Couldn't open config section '%s'", SectionName);
310 return ControllersFound;
313 ConfigSetParameter(pConfig, "device", M64TYPE_INT, &iDeviceIdx);
317 DebugMessage(M64MSG_ERROR, "Unknown keyword '%s' in %s", pchCurLine, INI_FILE_NAME);
322 /* unhandled line in .ini file */
323 DebugMessage(M64MSG_ERROR, "Invalid line in %s: '%s'", INI_FILE_NAME, pchCurLine);
326 if (eParseState == E_PARAM_READ)
328 /* we've finished parsing all parameters for the discovered input device, which is the last in the .ini file */
330 return ControllersFound;