mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
464 lines
11 KiB
C
464 lines
11 KiB
C
/**
|
|
* Mupen64 - util.c
|
|
* Copyright (C) 2002 Hacktarux
|
|
*
|
|
* Mupen64 homepage: http://mupen64.emulation64.com
|
|
* email address: hacktarux@yahoo.fr
|
|
*
|
|
* If you want to contribute to the project please contact
|
|
* me first (maybe someone is already making what you are
|
|
* planning to do).
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/
|
|
* or modify it under the terms of the GNU General Public Li-
|
|
* cence as published by the Free Software Foundation; either
|
|
* version 2 of the Licence, or any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be use-
|
|
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
|
|
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public Licence for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* Licence along with this program; if not, write to the Free
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
|
* USA.
|
|
*
|
|
**/
|
|
|
|
/**
|
|
* Provides common utilities to the rest of the code:
|
|
* -String functions
|
|
* -Doubly-linked list
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <SDL.h>
|
|
|
|
#include "util.h"
|
|
|
|
/** trim
|
|
* Removes leading and trailing whitespace from str. Function modifies str
|
|
* and also returns modified string.
|
|
*/
|
|
char *trim(char *str)
|
|
{
|
|
char *p = str;
|
|
|
|
while (isspace(*p))
|
|
p++;
|
|
|
|
if(str != p)
|
|
strcpy(str, p);
|
|
|
|
p = str + strlen(str) - 1;
|
|
if (p > str)
|
|
{
|
|
while (isspace(*p))
|
|
p--;
|
|
*(++p) = '\0';
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
/** event_to_str
|
|
* Creates a string representation of an SDL input event. If the event is
|
|
* not supported by this function, NULL is returned.
|
|
*
|
|
* Notes:
|
|
* -This function assumes SDL events are already initialized.
|
|
* -It is up to the caller to free the string memory allocated by this
|
|
* function.
|
|
*/
|
|
char *event_to_str(const SDL_Event *event)
|
|
{
|
|
char *event_str = NULL;
|
|
|
|
switch(event->type)
|
|
{
|
|
case SDL_JOYAXISMOTION:
|
|
if(event->jaxis.value >= 15000 || event->jaxis.value <= -15000)
|
|
{
|
|
event_str = malloc(10);
|
|
snprintf(event_str, 10, "J%dA%d%c",
|
|
event->jaxis.which,
|
|
event->jaxis.axis,
|
|
event->jaxis.value > 0? '+' : '-');
|
|
}
|
|
break;
|
|
|
|
case SDL_JOYBUTTONDOWN:
|
|
case SDL_JOYBUTTONUP:
|
|
event_str = malloc(10);
|
|
snprintf(event_str, 10, "J%dB%d",
|
|
event->jbutton.which,
|
|
event->jbutton.button);
|
|
break;
|
|
|
|
case SDL_JOYHATMOTION:
|
|
event_str = malloc(10);
|
|
snprintf(event_str, 10, "J%dH%dV%d",
|
|
event->jhat.which,
|
|
event->jhat.hat,
|
|
event->jhat.value);
|
|
break;
|
|
}
|
|
|
|
return event_str;
|
|
}
|
|
|
|
/** event_active
|
|
* Returns 1 if the specified joystick event is currently active. This
|
|
* function expects an input string of the same form output by event_to_str.
|
|
*/
|
|
int event_active(const char *event_str)
|
|
{
|
|
char device, joy_input_type, axis_direction;
|
|
int dev_number, input_number, input_value;
|
|
SDL_Joystick *joystick = NULL;
|
|
|
|
// empty string
|
|
if(!event_str || strlen(event_str) == 0) return 0;
|
|
|
|
// joystick event
|
|
if(event_str[0] == 'J')
|
|
{
|
|
// parse string depending on type of joystick input
|
|
switch(event_str[2])
|
|
{
|
|
// axis
|
|
case 'A':
|
|
sscanf(event_str, "%c%d%c%d%c", &device, &dev_number,
|
|
&joy_input_type, &input_number, &axis_direction);
|
|
break;
|
|
// hat
|
|
case 'H':
|
|
sscanf(event_str, "%c%d%c%dV%d", &device, &dev_number,
|
|
&joy_input_type, &input_number, &input_value);
|
|
break;
|
|
// button
|
|
case 'B':
|
|
sscanf(event_str, "%c%d%c%d", &device, &dev_number,
|
|
&joy_input_type, &input_number);
|
|
break;
|
|
}
|
|
|
|
joystick = SDL_JoystickOpen(dev_number);
|
|
SDL_JoystickUpdate();
|
|
switch(joy_input_type)
|
|
{
|
|
case 'A':
|
|
if(axis_direction == '-')
|
|
return SDL_JoystickGetAxis(joystick, input_number) < -15000;
|
|
else
|
|
return SDL_JoystickGetAxis(joystick, input_number) > 15000;
|
|
return (int)SDL_JoystickGetButton(joystick, input_number);
|
|
break;
|
|
case 'B':
|
|
return (int)SDL_JoystickGetButton(joystick, input_number);
|
|
break;
|
|
case 'H':
|
|
return SDL_JoystickGetHat(joystick, input_number) == input_value;
|
|
break;
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// keyboard event
|
|
if(event_str[0] == 'K')
|
|
{
|
|
// TODO
|
|
}
|
|
}
|
|
|
|
/** key_pressed
|
|
* Returns 1 if the given key is currently pressed.
|
|
*/
|
|
int key_pressed(SDLKey k)
|
|
{
|
|
Uint8 *key_states;
|
|
int num_keys;
|
|
|
|
SDL_PumpEvents(); // update input state array
|
|
key_states = SDL_GetKeyState(&num_keys);
|
|
|
|
if(k >= num_keys)
|
|
return 0;
|
|
|
|
return key_states[k];
|
|
}
|
|
|
|
/** file utilities **/
|
|
|
|
/** isfile
|
|
* Returns TRUE if given file path exists and is a regular file
|
|
*/
|
|
int isfile(char *path)
|
|
{
|
|
struct stat sbuf;
|
|
|
|
return (stat(path, &sbuf) == 0) && S_ISREG(sbuf.st_mode);
|
|
}
|
|
|
|
/** isdir
|
|
* Returns TRUE if given file path exists and is a directory
|
|
*/
|
|
int isdir(char *path)
|
|
{
|
|
struct stat sbuf;
|
|
|
|
return (stat(path, &sbuf) == 0) && S_ISDIR(sbuf.st_mode);
|
|
}
|
|
|
|
/** copyfile
|
|
* copies file at src to a new file dest. If dest exists, its contents will be truncated and replaced.
|
|
*/
|
|
int copyfile(char *src, char *dest)
|
|
{
|
|
FILE *to, *from;
|
|
char c;
|
|
|
|
if((from = fopen(src, "r")) == NULL)
|
|
return -1;
|
|
|
|
if((to = fopen(dest, "w")) == NULL)
|
|
{
|
|
fclose(from);
|
|
return -2;
|
|
}
|
|
|
|
while(!feof(from))
|
|
{
|
|
c = fgetc(from);
|
|
if(ferror(from))
|
|
{
|
|
fclose(from);
|
|
fclose(to);
|
|
unlink(dest);
|
|
return -3;
|
|
}
|
|
if(!feof(from))
|
|
fputc(c, to);
|
|
|
|
if(ferror(to))
|
|
{
|
|
fclose(from);
|
|
fclose(to);
|
|
unlink(dest);
|
|
return -4;
|
|
}
|
|
}
|
|
|
|
fclose(from);
|
|
fclose(to);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/** linked list functions **/
|
|
|
|
/** list_append
|
|
* Allocates a new list node, attaches it to the end of list and sets the
|
|
* node data pointer to data.
|
|
* Returns - the new list node.
|
|
*/
|
|
list_node_t *list_append(list_t *list, void *data)
|
|
{
|
|
list_node_t *new_node,
|
|
*last_node;
|
|
|
|
if(list_empty(*list))
|
|
{
|
|
(*list) = malloc(sizeof(list_node_t));
|
|
(*list)->data = data;
|
|
(*list)->prev = NULL;
|
|
(*list)->next = NULL;
|
|
return *list;
|
|
}
|
|
|
|
// find end of list
|
|
last_node = *list;
|
|
while(last_node->next != NULL)
|
|
last_node = last_node->next;
|
|
|
|
// create new node and return it
|
|
last_node->next = new_node = malloc(sizeof(list_node_t));
|
|
new_node->data = data;
|
|
new_node->prev = last_node;
|
|
new_node->next = NULL;
|
|
|
|
return new_node;
|
|
}
|
|
|
|
/** list_node_delete
|
|
* Deallocates and removes given node from the given list. It is up to the
|
|
* user to free any memory allocated for the node data before calling this
|
|
* function. Also, it is assumed that node is an element of list.
|
|
*/
|
|
void list_node_delete(list_t *list, list_node_t *node)
|
|
{
|
|
if(node == NULL || *list == NULL) return;
|
|
|
|
if(node->prev != NULL)
|
|
node->prev->next = node->next;
|
|
else
|
|
*list = node->next; // node is first node, update list pointer
|
|
|
|
if(node->next != NULL)
|
|
node->next->prev = node->prev;
|
|
|
|
free(node);
|
|
}
|
|
|
|
/** list_delete
|
|
* Deallocates and removes all nodes from the given list. It is up to the
|
|
* user to free any memory allocated for all node data before calling this
|
|
* function.
|
|
*/
|
|
void list_delete(list_t *list)
|
|
{
|
|
list_node_t *prev = NULL,
|
|
*curr = NULL;
|
|
|
|
// delete all list nodes in the list
|
|
list_foreach(*list, curr)
|
|
{
|
|
if(prev != NULL)
|
|
free(prev);
|
|
|
|
// if we're on the last node, delete it
|
|
if(curr->next == NULL)
|
|
free(curr);
|
|
else
|
|
prev = curr;
|
|
}
|
|
|
|
*list = NULL;
|
|
}
|
|
|
|
/** list_node_move_front
|
|
* Moves the given node to the first position of list. It is assumed that
|
|
* node is an element of list.
|
|
*/
|
|
void list_node_move_front(list_t *list, list_node_t *node)
|
|
{
|
|
list_node_t *tmp;
|
|
|
|
if(node == NULL ||
|
|
*list == NULL ||
|
|
node == *list)
|
|
return;
|
|
|
|
tmp = *list;
|
|
node->prev->next = node->next;
|
|
if(node->next != NULL)
|
|
node->next->prev = node->prev;
|
|
node->prev = NULL;
|
|
node->next = *list;
|
|
(*list)->prev = node;
|
|
*list = node;
|
|
}
|
|
|
|
/** list_node_move_back
|
|
* Moves the given node to the last position of list. It is assumed that
|
|
* node is an element of list.
|
|
*/
|
|
void list_node_move_back(list_t *list, list_node_t *node)
|
|
{
|
|
list_node_t *tmp;
|
|
|
|
tmp = list_last_node(*list);
|
|
|
|
if(node == NULL ||
|
|
*list == NULL ||
|
|
node == tmp)
|
|
return;
|
|
|
|
node->next->prev = node->prev;
|
|
if(node->prev != NULL)
|
|
node->prev->next = node->next;
|
|
else
|
|
*list = node->next; // first node is being moved, update list pointer
|
|
tmp->next = node;
|
|
node->prev = tmp;
|
|
node->next = NULL;
|
|
}
|
|
|
|
/** list_nth_node_data
|
|
* Returns the nth node in list. If n is out of range, NULL is returned.
|
|
*/
|
|
void *list_nth_node_data(list_t list, int n)
|
|
{
|
|
list_node_t *curr = NULL;
|
|
|
|
list_foreach(list, curr)
|
|
{
|
|
if(n-- == 0)
|
|
break;
|
|
}
|
|
|
|
return curr != NULL ? curr->data : curr;
|
|
}
|
|
|
|
/** list_last_node
|
|
* Returns the last node in list.
|
|
*/
|
|
list_node_t *list_last_node(list_t list)
|
|
{
|
|
if(list != NULL)
|
|
{
|
|
while(list->next != NULL)
|
|
list = list->next;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/** list_empty
|
|
* Returns 1 if list is empty, else 0.
|
|
*/
|
|
int inline list_empty(list_t list)
|
|
{
|
|
return list == NULL;
|
|
}
|
|
|
|
/** list_length
|
|
* Returns the number of elements in list
|
|
*/
|
|
int list_length(list_t list)
|
|
{
|
|
int len = 0;
|
|
list_node_t *curr;
|
|
|
|
list_foreach(list, curr)
|
|
{
|
|
len++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/** list_find_node
|
|
* Searches the given list for a node whose data pointer matches the given data pointer.
|
|
* If found, returns a pointer to the node, else, returns NULL.
|
|
*/
|
|
list_node_t *list_find_node(list_t list, void *data)
|
|
{
|
|
list_node_t *node = NULL;
|
|
|
|
list_foreach(list, node)
|
|
if(node->data == data)
|
|
break;
|
|
|
|
return node;
|
|
}
|
|
|