More linking, compilation

This commit is contained in:
Akop Karapetyan 2019-10-09 12:24:39 -07:00 committed by tmaul
parent 335873119a
commit 2d55a09667
14 changed files with 2793 additions and 24 deletions

View File

@ -1,6 +1,6 @@
alldir += burner burner/pi burner/sdl dep/libs/libpng dep/libs/lib7z dep/libs/zlib intf intf/video \
intf/video/scalers intf/video/pi intf/audio intf/audio/sdl intf/input intf/input/pi intf/cd intf/cd/sdl \
intf/perfcount intf/perfcount/pi dep/generated
intf/perfcount intf/perfcount/pi dep/generated dep/pi/cjson
depobj += neocdlist.o \
\
@ -12,10 +12,13 @@ depobj += neocdlist.o \
png.o pngerror.o pngget.o pngmem.o pngpread.o pngread.o pngrio.o pngrtran.o pngrutil.o pngset.o pngtrans.o pngwio.o \
pngwrite.o pngwtran.o pngwutil.o \
\
aud_dsp.o aud_interface.o cd_interface.o inp_interface.o interface.o lowpass2.o prf_interface.o vid_interface.o \
aud_dsp.o aud_interface.o cd_interface.o inp_interface.o interface.o lowpass2.o vid_interface.o \
vid_softfx.o vid_support.o \
\
2xpm.o 2xsai.o ddt3x.o epx.o hq2xs.o hq2xs_16.o xbr.o
2xpm.o 2xsai.o ddt3x.o epx.o hq2xs.o hq2xs_16.o xbr.o \
\
inp_udev.o inp_pi.o inp_pi_keys.o aud_sdl.o support_paths.o ips_manager.o scrn.o cJSON.o \
cd_isowav.o cdsound.o
ifdef INCLUDE_7Z_SUPPORT
depobj += un7z.o \

View File

@ -29,7 +29,6 @@ undefine BUILD_A68K
undefine UNICODE
#
# Specify paths/files
#
@ -40,8 +39,12 @@ srcdir = src/
include makefile.burn_rules
include makefile.burner_pi_rules
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated -I$(srcdir)dep/pi/include \
-I/usr/include/SDL
incdir = $(foreach dir,$(alldir),-I$(srcdir)$(dir)) -I$(objdir)dep/generated \
-I/local/include -I$(srcdir)dep/pi/include -I$(srcdir)intf/input/sdl \
-I/usr/include/SDL -I/opt/vc/include/interface/vcos/pthreads \
-I/opt/vc/include/interface/vmcs_host/linux -I/opt/vc/include
lib = -lstdc++ -lSDL -lpthread -ludev -L/usr/X11R6/lib -L/opt/vc/lib
autdep = $(depobj:.o=.d)
drvdep = $(drvsrc:.o=.d)
@ -101,7 +104,7 @@ CXX = g++
LD = $(CXX)
AS = nasm
LDFLAGS = -static
#LDFLAGS = -static
CFLAGS = -O2 -fomit-frame-pointer -Wno-write-strings \
-Wall -Wno-long-long -Wno-sign-compare -Wno-uninitialized -Wno-unused \
@ -192,11 +195,6 @@ else
LDFLAGS += -s
endif
ifdef BUILD_X86_ASM
CFLAGS += -mmmx
CXXFLAGS += -mmmx
endif
# For zlib
DEF := $(DEF) -DNO_VIZ -D_LARGEFILE64_SOURCE=0 -D_FILE_OFFSET_BITS=32
@ -254,11 +252,11 @@ endif
ifeq ($(MAKELEVEL),2)
$(objdir)/drivers.o: $(autdrv)
$(objdir)drivers.o: $(autdrv)
@echo Linking drivers...
@$(LD) -r -nostdlib -o $@ $^
$(NAME): $(allobj) $(objdir)/drivers.o
$(NAME): $(allobj) $(objdir)drivers.o
@echo
@echo Linking executable... $(NAME)
@$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(lib)
@ -339,7 +337,7 @@ $(objdir)cpu/m68k/m68kops.o: $(objdir)cpu/m68k/m68kmake $(objdir)dep/generated/m
@$(CC) $(CFLAGS) -c $(objdir)dep/generated/m68kops.c -o $(objdir)cpu/m68k/m68kops.o
$(objdir)dep/generated/m68kops.h $(objdir)dep/generated/m68kops.c: $(objdir)cpu/m68k/m68kmake $(srcdir)cpu/m68k/m68k_in.c
$(objdir)/cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
$(objdir)cpu/m68k/m68kmake $(objdir)dep/generated/ $(srcdir)cpu/m68k/m68k_in.c
$(objdir)cpu/m68k/m68kmake: $(srcdir)cpu/m68k/m68kmake.c
@echo Compiling Musashi MC680x0 core \(m68kmake.c\)...

View File

@ -1,8 +1,13 @@
#include "burner.h"
void Reinitialise()
{
//POST_INITIALISE_MESSAGE;
VidReInitialise();
}
#include "burner.h"
void Reinitialise()
{
//POST_INITIALISE_MESSAGE;
VidReInitialise();
}
INT32 is_netgame_or_recording() // returns: 1 = netgame, 2 = recording/playback
{
return 0;
}

20
src/dep/pi/cjson/LICENSE Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

247
src/dep/pi/cjson/README Normal file
View File

@ -0,0 +1,247 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
Welcome to cJSON.
cJSON aims to be the dumbest possible parser that you can get your job done with.
It's a single file of C, and a single header file.
JSON is described best here: http://www.json.org/
It's like XML, but fat-free. You use it to move data around, store things, or just
generally represent your program's state.
First up, how do I build?
Add cJSON.c to your project, and put cJSON.h somewhere in the header search path.
For example, to build the test app:
gcc cJSON.c test.c -o test -lm
./test
As a library, cJSON exists to take away as much legwork as it can, but not get in your way.
As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it
in one of two modes: Auto and Manual. Let's have a quick run-through.
I lifted some JSON from this page: http://www.json.org/fatfree.html
That page inspired me to write cJSON, which is a parser that tries to share the same
philosophy as JSON itself. Simple, dumb, out of the way.
Some JSON:
{
"name": "Jack (\"Bee\") Nimble",
"format": {
"type": "rect",
"width": 1920,
"height": 1080,
"interlace": false,
"frame rate": 24
}
}
Assume that you got this from a file, a webserver, or magic JSON elves, whatever,
you have a char * to it. Everything is a cJSON struct.
Get it parsed:
cJSON *root = cJSON_Parse(my_json_string);
This is an object. We're in C. We don't have objects. But we do have structs.
What's the framerate?
cJSON *format = cJSON_GetObjectItem(root,"format");
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint;
Want to change the framerate?
cJSON_GetObjectItem(format,"frame rate")->valueint=25;
Back to disk?
char *rendered=cJSON_Print(root);
Finished? Delete the root (this takes care of everything else).
cJSON_Delete(root);
That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers
before you dereference them. If you want to see how you'd build this struct in code?
cJSON *root,*fmt;
root=cJSON_CreateObject();
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
cJSON_AddStringToObject(fmt,"type", "rect");
cJSON_AddNumberToObject(fmt,"width", 1920);
cJSON_AddNumberToObject(fmt,"height", 1080);
cJSON_AddFalseToObject (fmt,"interlace");
cJSON_AddNumberToObject(fmt,"frame rate", 24);
Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup.
Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and
a few from elsewhere.
What about manual mode? First up you need some detail.
Let's cover how the cJSON objects represent the JSON data.
cJSON doesn't distinguish arrays from objects in handling; just type.
Each cJSON has, potentially, a child, siblings, value, a name.
The root object has: Object Type and a Child
The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling:
Sibling has type Object, name "format", and a child.
That child has type String, name "type", value "rect", and a sibling:
Sibling has type Number, name "width", value 1920, and a sibling:
Sibling has type Number, name "height", value 1080, and a sibling:
Sibling hs type False, name "interlace", and a sibling:
Sibling has type Number, name "frame rate", value 24
Here's the structure:
typedef struct cJSON {
struct cJSON *next,*prev;
struct cJSON *child;
int type;
char *valuestring;
int valueint;
double valuedouble;
char *string;
} cJSON;
By default all values are 0 unless set by virtue of being meaningful.
next/prev is a doubly linked list of siblings. next takes you to your sibling,
prev takes you back from your sibling to you.
Only objects and arrays have a "child", and it's the head of the doubly linked list.
A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0.
The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in
cJSON.h
A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read
valuedouble.
Any entry which is in the linked list which is the child of an object will have a "string"
which is the "name" of the entry. When I said "name" in the above example, that's "string".
"string" is the JSON name for the 'variable name' if you will.
Now you can trivially walk the lists, recursively, and parse as you please.
You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take
the root object, and traverse the structure (which is, formally, an N-tree),
and tokenise as you please. If you wanted to build a callback style parser, this is how
you'd do it (just an example, since these things are very specific):
void parse_and_callback(cJSON *item,const char *prefix)
{
while (item)
{
char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2);
sprintf(newprefix,"%s/%s",prefix,item->name);
int dorecurse=callback(newprefix, item->type, item);
if (item->child && dorecurse) parse_and_callback(item->child,newprefix);
item=item->next;
free(newprefix);
}
}
The prefix process will build you a separated list, to simplify your callback handling.
The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or
let you invoke it per-item. For the item above, your callback might look like this:
int callback(const char *name,int type,cJSON *item)
{
if (!strcmp(name,"name")) { /* populate name */ }
else if (!strcmp(name,"format/type") { /* handle "rect" */ }
else if (!strcmp(name,"format/width") { /* 800 */ }
else if (!strcmp(name,"format/height") { /* 600 */ }
else if (!strcmp(name,"format/interlace") { /* false */ }
else if (!strcmp(name,"format/frame rate") { /* 24 */ }
return 1;
}
Alternatively, you might like to parse iteratively.
You'd use:
void parse_object(cJSON *item)
{
int i; for (i=0;i<cJSON_GetArraySize(item);i++)
{
cJSON *subitem=cJSON_GetArrayItem(item,i);
// handle subitem.
}
}
Or, for PROPER manual mode:
void parse_object(cJSON *item)
{
cJSON *subitem=item->child;
while (subitem)
{
// handle subitem
if (subitem->child) parse_object(subitem->child);
subitem=subitem->next;
}
}
Of course, this should look familiar, since this is just a stripped-down version
of the callback-parser.
This should cover most uses you'll find for parsing. The rest should be possible
to infer.. and if in doubt, read the source! There's not a lot of it! ;)
In terms of constructing JSON data, the example code above is the right way to do it.
You can, of course, hand your sub-objects to other functions to populate.
Also, if you find a use for it, you can manually build the objects.
For instance, suppose you wanted to build an array of objects?
cJSON *objects[24];
cJSON *Create_array_of_anything(cJSON **items,int num)
{
int i;cJSON *prev, *root=cJSON_CreateArray();
for (i=0;i<24;i++)
{
if (!i) root->child=objects[i];
else prev->next=objects[i], objects[i]->prev=prev;
prev=objects[i];
}
return root;
}
and simply: Create_array_of_anything(objects,24);
cJSON doesn't make any assumptions about what order you create things in.
You can attach the objects, as above, and later add children to each
of those objects.
As soon as you call cJSON_Print, it renders the structure to text.
The test.c code shows how to handle a bunch of typical cases. If you uncomment
the code, it'll load, parse and print a bunch of test files, also from json.org,
which are more complex than I'd care to try and stash into a const char array[].
Enjoy cJSON!
- Dave Gamble, Aug 2009

750
src/dep/pi/cjson/cJSON.c Normal file
View File

@ -0,0 +1,750 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* cJSON */
/* JSON parser in C. */
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include "cJSON.h"
static const char *ep;
const char *cJSON_GetErrorPtr(void) {return ep;}
static int cJSON_strcasecmp(const char *s1,const char *s2)
{
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
static void *(*cJSON_malloc)(size_t sz) = malloc;
static void (*cJSON_free)(void *ptr) = free;
static char* cJSON_strdup(const char* str)
{
size_t len;
char* copy;
len = strlen(str) + 1;
if (!(copy = (char*)cJSON_malloc(len))) return 0;
memcpy(copy,str,len);
return copy;
}
void cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (!hooks) { /* Reset hooks */
cJSON_malloc = malloc;
cJSON_free = free;
return;
}
cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
cJSON_free = (hooks->free_fn)?hooks->free_fn:free;
}
/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{
cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
if (node) memset(node,0,sizeof(cJSON));
return node;
}
/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{
cJSON *next;
while (c)
{
next=c->next;
if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
cJSON_free(c);
c=next;
}
}
/* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item,const char *num)
{
double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
if (*num=='-') sign=-1,num++; /* Has sign? */
if (*num=='0') num++; /* is zero */
if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */
if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */
if (*num=='e' || *num=='E') /* Exponent? */
{ num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */
while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */
}
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
item->valuedouble=n;
item->valueint=(int)n;
item->type=cJSON_Number;
return num;
}
static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; }
typedef struct {char *buffer; int length; int offset; } printbuffer;
static char* ensure(printbuffer *p,int needed)
{
char *newbuffer;int newsize;
if (!p || !p->buffer) return 0;
needed+=p->offset;
if (needed<=p->length) return p->buffer+p->offset;
newsize=pow2gt(needed);
newbuffer=(char*)cJSON_malloc(newsize);
if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
cJSON_free(p->buffer);
p->length=newsize;
p->buffer=newbuffer;
return newbuffer+p->offset;
}
static int update(printbuffer *p)
{
char *str;
if (!p || !p->buffer) return 0;
str=p->buffer+p->offset;
return p->offset+strlen(str);
}
/* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item,printbuffer *p)
{
char *str=0;
double d=item->valuedouble;
if (d==0)
{
if (p) str=ensure(p,2);
else str=(char*)cJSON_malloc(2); /* special case for 0. */
if (str) strcpy(str,"0");
}
else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN)
{
if (p) str=ensure(p,21);
else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
if (str) sprintf(str,"%d",item->valueint);
}
else
{
if (p) str=ensure(p,64);
else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */
if (str)
{
if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d);
else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d);
else sprintf(str,"%f",d);
}
}
return str;
}
static unsigned parse_hex4(const char *str)
{
unsigned h=0;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
h=h<<4;str++;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
h=h<<4;str++;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
h=h<<4;str++;
if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
return h;
}
/* Parse the input text into an unescaped cstring, and populate item. */
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item,const char *str)
{
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
if (*str!='\"') {ep=str;return 0;} /* not a string! */
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
if (!out) return 0;
ptr=str+1;ptr2=out;
while (*ptr!='\"' && *ptr)
{
if (*ptr!='\\') *ptr2++=*ptr++;
else
{
ptr++;
switch (*ptr)
{
case 'b': *ptr2++='\b'; break;
case 'f': *ptr2++='\f'; break;
case 'n': *ptr2++='\n'; break;
case 'r': *ptr2++='\r'; break;
case 't': *ptr2++='\t'; break;
case 'u': /* transcode utf16 to utf8. */
uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */
if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */
{
if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */
uc2=parse_hex4(ptr+3);ptr+=6;
if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */
uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
}
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
switch (len) {
case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
case 1: *--ptr2 =(uc | firstByteMark[len]);
}
ptr2+=len;
break;
default: *ptr2++=*ptr; break;
}
ptr++;
}
}
*ptr2=0;
if (*ptr=='\"') ptr++;
item->valuestring=out;
item->type=cJSON_String;
return ptr;
}
/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str,printbuffer *p)
{
const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
if (!flag)
{
len=ptr-str;
if (p) out=ensure(p,len+3);
else out=(char*)cJSON_malloc(len+3);
if (!out) return 0;
ptr2=out;*ptr2++='\"';
strcpy(ptr2,str);
ptr2[len]='\"';
ptr2[len+1]=0;
return out;
}
if (!str)
{
if (p) out=ensure(p,3);
else out=(char*)cJSON_malloc(3);
if (!out) return 0;
strcpy(out,"\"\"");
return out;
}
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
if (p) out=ensure(p,len+3);
else out=(char*)cJSON_malloc(len+3);
if (!out) return 0;
ptr2=out;ptr=str;
*ptr2++='\"';
while (*ptr)
{
if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
else
{
*ptr2++='\\';
switch (token=*ptr++)
{
case '\\': *ptr2++='\\'; break;
case '\"': *ptr2++='\"'; break;
case '\b': *ptr2++='b'; break;
case '\f': *ptr2++='f'; break;
case '\n': *ptr2++='n'; break;
case '\r': *ptr2++='r'; break;
case '\t': *ptr2++='t'; break;
default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */
}
}
}
*ptr2++='\"';*ptr2++=0;
return out;
}
/* Invote print_string_ptr (which is useful) on an item. */
static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);}
/* Predeclare these prototypes. */
static const char *parse_value(cJSON *item,const char *value);
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_array(cJSON *item,const char *value);
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_object(cJSON *item,const char *value);
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
/* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
/* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{
const char *end=0;
cJSON *c=cJSON_New_Item();
ep=0;
if (!c) return 0; /* memory fail */
end=parse_value(c,skip(value));
if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}
if (return_parse_end) *return_parse_end=end;
return c;
}
/* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
/* Render a cJSON item/entity/structure to text. */
char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}
char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
{
printbuffer p;
p.buffer=(char*)cJSON_malloc(prebuffer);
p.length=prebuffer;
p.offset=0;
return print_value(item,0,fmt,&p);
return p.buffer;
}
/* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value)
{
if (!value) return 0; /* Fail on null. */
if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; }
if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; }
if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; }
if (*value=='\"') { return parse_string(item,value); }
if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); }
if (*value=='[') { return parse_array(item,value); }
if (*value=='{') { return parse_object(item,value); }
ep=value;return 0; /* failure. */
}
/* Render a value to text. */
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
{
char *out=0;
if (!item) return 0;
if (p)
{
switch ((item->type)&255)
{
case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;}
case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;}
case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;}
case cJSON_Number: out=print_number(item,p);break;
case cJSON_String: out=print_string(item,p);break;
case cJSON_Array: out=print_array(item,depth,fmt,p);break;
case cJSON_Object: out=print_object(item,depth,fmt,p);break;
}
}
else
{
switch ((item->type)&255)
{
case cJSON_NULL: out=cJSON_strdup("null"); break;
case cJSON_False: out=cJSON_strdup("false");break;
case cJSON_True: out=cJSON_strdup("true"); break;
case cJSON_Number: out=print_number(item,0);break;
case cJSON_String: out=print_string(item,0);break;
case cJSON_Array: out=print_array(item,depth,fmt,0);break;
case cJSON_Object: out=print_object(item,depth,fmt,0);break;
}
}
return out;
}
/* Build an array from input text. */
static const char *parse_array(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='[') {ep=value;return 0;} /* not an array! */
item->type=cJSON_Array;
value=skip(value+1);
if (*value==']') return value+1; /* empty array. */
item->child=child=cJSON_New_Item();
if (!item->child) return 0; /* memory fail */
value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_value(child,skip(value+1)));
if (!value) return 0; /* memory fail */
}
if (*value==']') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
/* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
{
char **entries;
char *out=0,*ptr,*ret;int len=5;
cJSON *child=item->child;
int numentries=0,i=0,fail=0;
size_t tmplen=0;
/* How many entries in the array? */
while (child) numentries++,child=child->next;
/* Explicitly handle numentries==0 */
if (!numentries)
{
if (p) out=ensure(p,3);
else out=(char*)cJSON_malloc(3);
if (out) strcpy(out,"[]");
return out;
}
if (p)
{
/* Compose the output array. */
i=p->offset;
ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++;
child=item->child;
while (child && !fail)
{
print_value(child,depth+1,fmt,p);
p->offset=update(p);
if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
child=child->next;
}
ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0;
out=(p->buffer)+i;
}
else
{
/* Allocate an array to hold the values for each */
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!entries) return 0;
memset(entries,0,numentries*sizeof(char*));
/* Retrieve all the results: */
child=item->child;
while (child && !fail)
{
ret=print_value(child,depth+1,fmt,0);
entries[i++]=ret;
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
child=child->next;
}
/* If we didn't fail, try to malloc the output string */
if (!fail) out=(char*)cJSON_malloc(len);
/* If that fails, we fail. */
if (!out) fail=1;
/* Handle failure. */
if (fail)
{
for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
cJSON_free(entries);
return 0;
}
/* Compose the output array. */
*out='[';
ptr=out+1;*ptr=0;
for (i=0;i<numentries;i++)
{
tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
cJSON_free(entries[i]);
}
cJSON_free(entries);
*ptr++=']';*ptr++=0;
}
return out;
}
/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='{') {ep=value;return 0;} /* not an object! */
item->type=cJSON_Object;
value=skip(value+1);
if (*value=='}') return value+1; /* empty array. */
item->child=child=cJSON_New_Item();
if (!item->child) return 0;
value=skip(parse_string(child,skip(value)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
while (*value==',')
{
cJSON *new_item;
if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */
child->next=new_item;new_item->prev=child;child=new_item;
value=skip(parse_string(child,skip(value+1)));
if (!value) return 0;
child->string=child->valuestring;child->valuestring=0;
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
}
if (*value=='}') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
/* Render an object to text. */
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
{
char **entries=0,**names=0;
char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
cJSON *child=item->child;
int numentries=0,fail=0;
size_t tmplen=0;
/* Count the number of entries. */
while (child) numentries++,child=child->next;
/* Explicitly handle empty object case */
if (!numentries)
{
if (p) out=ensure(p,fmt?depth+4:3);
else out=(char*)cJSON_malloc(fmt?depth+4:3);
if (!out) return 0;
ptr=out;*ptr++='{';
if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}
*ptr++='}';*ptr++=0;
return out;
}
if (p)
{
/* Compose the output: */
i=p->offset;
len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0;
*ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len;
child=item->child;depth++;
while (child)
{
if (fmt)
{
ptr=ensure(p,depth); if (!ptr) return 0;
for (j=0;j<depth;j++) *ptr++='\t';
p->offset+=depth;
}
print_string_ptr(child->string,p);
p->offset=update(p);
len=fmt?2:1;
ptr=ensure(p,len); if (!ptr) return 0;
*ptr++=':';if (fmt) *ptr++='\t';
p->offset+=len;
print_value(child,depth,fmt,p);
p->offset=update(p);
len=(fmt?1:0)+(child->next?1:0);
ptr=ensure(p,len+1); if (!ptr) return 0;
if (child->next) *ptr++=',';
if (fmt) *ptr++='\n';*ptr=0;
p->offset+=len;
child=child->next;
}
ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0;
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr=0;
out=(p->buffer)+i;
}
else
{
/* Allocate space for the names and the objects */
entries=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!entries) return 0;
names=(char**)cJSON_malloc(numentries*sizeof(char*));
if (!names) {cJSON_free(entries);return 0;}
memset(entries,0,sizeof(char*)*numentries);
memset(names,0,sizeof(char*)*numentries);
/* Collect all the results into our arrays: */
child=item->child;depth++;if (fmt) len+=depth;
while (child)
{
names[i]=str=print_string_ptr(child->string,0);
entries[i++]=ret=print_value(child,depth,fmt,0);
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
child=child->next;
}
/* Try to allocate the output string */
if (!fail) out=(char*)cJSON_malloc(len);
if (!out) fail=1;
/* Handle failure */
if (fail)
{
for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
cJSON_free(names);cJSON_free(entries);
return 0;
}
/* Compose the output: */
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
for (i=0;i<numentries;i++)
{
if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
*ptr++=':';if (fmt) *ptr++='\t';
strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
if (i!=numentries-1) *ptr++=',';
if (fmt) *ptr++='\n';*ptr=0;
cJSON_free(names[i]);cJSON_free(entries[i]);
}
cJSON_free(names);cJSON_free(entries);
if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
*ptr++='}';*ptr++=0;
}
return out;
}
/* Get Array size/item / object item. */
int cJSON_GetArraySize(cJSON *array) {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
/* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
/* Utility for handling references. */
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
/* Add item to array/object. */
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
/* Replace array/object items with new ones. */
void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
/* Create basic types: */
cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
/* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
/* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
{
cJSON *newitem,*cptr,*nptr=0,*newchild;
/* Bail on bad ptr */
if (!item) return 0;
/* Create new item */
newitem=cJSON_New_Item();
if (!newitem) return 0;
/* Copy over all vars */
newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}}
if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}}
/* If non-recursive, then we're done! */
if (!recurse) return newitem;
/* Walk the ->next chain for the child. */
cptr=item->child;
while (cptr)
{
newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */
if (!newchild) {cJSON_Delete(newitem);return 0;}
if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */
else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */
cptr=cptr->next;
}
return newitem;
}
void cJSON_Minify(char *json)
{
char *into=json;
while (*json)
{
if (*json==' ') json++;
else if (*json=='\t') json++; /* Whitespace characters. */
else if (*json=='\r') json++;
else if (*json=='\n') json++;
else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */
else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */
else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
else *into++=*json++; /* All other characters. */
}
*into=0; /* and null-terminate. */
}

149
src/dep/pi/cjson/cJSON.h Normal file
View File

@ -0,0 +1,149 @@
/*
Copyright (c) 2009 Dave Gamble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* The type of the item, as above. */
char *valuestring; /* The item's string, if type==cJSON_String */
int valueint; /* The item's number, if type==cJSON_Number */
double valuedouble; /* The item's number, if type==cJSON_Number */
char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;
typedef struct cJSON_Hooks {
void *(*malloc_fn)(size_t sz);
void (*free_fn)(void *ptr);
} cJSON_Hooks;
/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c);
/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item "string" from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);
/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);
/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
/* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!=0, it will duplicate any children connected to the item.
The item->next and ->prev pointers are always zero on return from Duplicate. */
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
extern void cJSON_Minify(char *json);
/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val))
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,342 @@
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "cJSON_Utils.h"
static int cJSONUtils_strcasecmp(const char *s1,const char *s2)
{
if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
/* JSON Pointer implementation: */
static int cJSONUtils_Pstrcasecmp(const char *a,const char *e)
{
if (!a || !e) return (a==e)?0:1;
for (;*a && *e && *e!='/';a++,e++) {
if (*e=='~') {if (!(e[1]=='0' && *a=='~') && !(e[1]=='1' && *a=='/')) return 1; else e++;}
else if (tolower(*a)!=tolower(*e)) return 1;
}
if ((*e!=0 && *e!='/') != (*a!=0)) return 1;
return 0;
}
static int cJSONUtils_PointerEncodedstrlen(const char *s) {int l=0;for (;*s;s++,l++) if (*s=='~' || *s=='/') l++;return l;}
static void cJSONUtils_PointerEncodedstrcpy(char *d,const char *s)
{
for (;*s;s++)
{
if (*s=='/') {*d++='~';*d++='1';}
else if (*s=='~') {*d++='~';*d++='0';}
else *d++=*s;
}
*d=0;
}
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object,cJSON *target)
{
int type=object->type,c=0;cJSON *obj=0;
if (object==target) return strdup("");
for (obj=object->child;obj;obj=obj->next,c++)
{
char *found=cJSONUtils_FindPointerFromObjectTo(obj,target);
if (found)
{
if (type==cJSON_Array)
{
char *ret=(char*)malloc(strlen(found)+23);
sprintf(ret,"/%d%s",c,found);
free(found);
return ret;
}
else if (type==cJSON_Object)
{
char *ret=(char*)malloc(strlen(found)+cJSONUtils_PointerEncodedstrlen(obj->string)+2);
*ret='/';cJSONUtils_PointerEncodedstrcpy(ret+1,obj->string);
strcat(ret,found);
free(found);
return ret;
}
free(found);
return 0;
}
}
return 0;
}
cJSON *cJSONUtils_GetPointer(cJSON *object,const char *pointer)
{
while (*pointer++=='/' && object)
{
if (object->type==cJSON_Array)
{
int which=0; while (*pointer>='0' && *pointer<='9') which=(10*which) + *pointer++ - '0';
if (*pointer && *pointer!='/') return 0;
object=cJSON_GetArrayItem(object,which);
}
else if (object->type==cJSON_Object)
{
object=object->child; while (object && cJSONUtils_Pstrcasecmp(object->string,pointer)) object=object->next; /* GetObjectItem. */
while (*pointer && *pointer!='/') pointer++;
}
else return 0;
}
return object;
}
/* JSON Patch implementation. */
static void cJSONUtils_InplaceDecodePointerString(char *string)
{
char *s2=string;
for (;*string;s2++,string++) *s2=(*string!='~')?(*string):((*(++string)=='0')?'~':'/');
*s2=0;
}
static cJSON *cJSONUtils_PatchDetach(cJSON *object,const char *path)
{
char *parentptr=0,*childptr=0;cJSON *parent=0,*ret=0;
parentptr=strdup(path); childptr=strrchr(parentptr,'/'); if (childptr) *childptr++=0;
parent=cJSONUtils_GetPointer(object,parentptr);
cJSONUtils_InplaceDecodePointerString(childptr);
if (!parent) ret=0; /* Couldn't find object to remove child from. */
else if (parent->type==cJSON_Array) ret=cJSON_DetachItemFromArray(parent,atoi(childptr));
else if (parent->type==cJSON_Object) ret=cJSON_DetachItemFromObject(parent,childptr);
free(parentptr);
return ret;
}
static int cJSONUtils_Compare(cJSON *a,cJSON *b)
{
if (a->type!=b->type) return -1; /* mismatched type. */
switch (a->type)
{
case cJSON_Number: return (a->valueint!=b->valueint || a->valuedouble!=b->valuedouble)?-2:0; /* numeric mismatch. */
case cJSON_String: return (strcmp(a->valuestring,b->valuestring)!=0)?-3:0; /* string mismatch. */
case cJSON_Array: for (a=a->child,b=b->child;a && b;a=a->next,b=b->next) {int err=cJSONUtils_Compare(a,b);if (err) return err;}
return (a || b)?-4:0; /* array size mismatch. */
case cJSON_Object:
cJSONUtils_SortObject(a);
cJSONUtils_SortObject(b);
a=a->child,b=b->child;
while (a && b)
{
int err;
if (cJSONUtils_strcasecmp(a->string,b->string)) return -6; /* missing member */
err=cJSONUtils_Compare(a,b);if (err) return err;
a=a->next,b=b->next;
}
return (a || b)?-5:0; /* object length mismatch */
default: break;
}
return 0;
}
static int cJSONUtils_ApplyPatch(cJSON *object,cJSON *patch)
{
cJSON *op=0,*path=0,*value=0,*parent=0;int opcode=0;char *parentptr=0,*childptr=0;
op=cJSON_GetObjectItem(patch,"op");
path=cJSON_GetObjectItem(patch,"path");
if (!op || !path) return 2; /* malformed patch. */
if (!strcmp(op->valuestring,"add")) opcode=0;
else if (!strcmp(op->valuestring,"remove")) opcode=1;
else if (!strcmp(op->valuestring,"replace"))opcode=2;
else if (!strcmp(op->valuestring,"move")) opcode=3;
else if (!strcmp(op->valuestring,"copy")) opcode=4;
else if (!strcmp(op->valuestring,"test")) return cJSONUtils_Compare(cJSONUtils_GetPointer(object,path->valuestring),cJSON_GetObjectItem(patch,"value"));
else return 3; /* unknown opcode. */
if (opcode==1 || opcode==2) /* Remove/Replace */
{
cJSON_Delete(cJSONUtils_PatchDetach(object,path->valuestring)); /* Get rid of old. */
if (opcode==1) return 0; /* For Remove, this is job done. */
}
if (opcode==3 || opcode==4) /* Copy/Move uses "from". */
{
cJSON *from=cJSON_GetObjectItem(patch,"from"); if (!from) return 4; /* missing "from" for copy/move. */
if (opcode==3) value=cJSONUtils_PatchDetach(object,from->valuestring);
if (opcode==4) value=cJSONUtils_GetPointer(object,from->valuestring);
if (!value) return 5; /* missing "from" for copy/move. */
if (opcode==4) value=cJSON_Duplicate(value,1);
if (!value) return 6; /* out of memory for copy/move. */
}
else /* Add/Replace uses "value". */
{
value=cJSON_GetObjectItem(patch,"value");
if (!value) return 7; /* missing "value" for add/replace. */
value=cJSON_Duplicate(value,1);
if (!value) return 8; /* out of memory for add/replace. */
}
/* Now, just add "value" to "path". */
parentptr=strdup(path->valuestring); childptr=strrchr(parentptr,'/'); if (childptr) *childptr++=0;
parent=cJSONUtils_GetPointer(object,parentptr);
cJSONUtils_InplaceDecodePointerString(childptr);
/* add, remove, replace, move, copy, test. */
if (!parent) {free(parentptr); return 9;} /* Couldn't find object to add to. */
else if (parent->type==cJSON_Array)
{
if (!strcmp(childptr,"-")) cJSON_AddItemToArray(parent,value);
else cJSON_InsertItemInArray(parent,atoi(childptr),value);
}
else if (parent->type==cJSON_Object)
{
cJSON_DeleteItemFromObject(parent,childptr);
cJSON_AddItemToObject(parent,childptr,value);
}
free(parentptr);
return 0;
}
int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches)
{
int err;
if (!patches->type==cJSON_Array) return 1; /* malformed patches. */
if (patches) patches=patches->child;
while (patches)
{
if ((err=cJSONUtils_ApplyPatch(object,patches))) return err;
patches=patches->next;
}
return 0;
}
static void cJSONUtils_GeneratePatch(cJSON *patches,const char *op,const char *path,const char *suffix,cJSON *val)
{
cJSON *patch=cJSON_CreateObject();
cJSON_AddItemToObject(patch,"op",cJSON_CreateString(op));
if (suffix)
{
char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(suffix)+2);
cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),suffix);
cJSON_AddItemToObject(patch,"path",cJSON_CreateString(newpath));
free(newpath);
}
else cJSON_AddItemToObject(patch,"path",cJSON_CreateString(path));
if (val) cJSON_AddItemToObject(patch,"value",cJSON_Duplicate(val,1));
cJSON_AddItemToArray(patches,patch);
}
void cJSONUtils_AddPatchToArray(cJSON *array,const char *op,const char *path,cJSON *val) {cJSONUtils_GeneratePatch(array,op,path,0,val);}
static void cJSONUtils_CompareToPatch(cJSON *patches,const char *path,cJSON *from,cJSON *to)
{
if (from->type!=to->type) {cJSONUtils_GeneratePatch(patches,"replace",path,0,to); return; }
switch (from->type)
{
case cJSON_Number:
if (from->valueint!=to->valueint || from->valuedouble!=to->valuedouble)
cJSONUtils_GeneratePatch(patches,"replace",path,0,to);
return;
case cJSON_String:
if (strcmp(from->valuestring,to->valuestring)!=0)
cJSONUtils_GeneratePatch(patches,"replace",path,0,to);
return;
case cJSON_Array:
{
int c;char *newpath=(char*)malloc(strlen(path)+23); /* Allow space for 64bit int. */
for (c=0,from=from->child,to=to->child;from && to;from=from->next,to=to->next,c++){
sprintf(newpath,"%s/%d",path,c); cJSONUtils_CompareToPatch(patches,newpath,from,to);
}
for (;from;from=from->next,c++) {sprintf(newpath,"%d",c); cJSONUtils_GeneratePatch(patches,"remove",path,newpath,0); }
for (;to;to=to->next,c++) cJSONUtils_GeneratePatch(patches,"add",path,"-",to);
free(newpath);
return;
}
case cJSON_Object:
{
cJSON *a,*b;
cJSONUtils_SortObject(from);
cJSONUtils_SortObject(to);
a=from->child,b=to->child;
while (a || b)
{
int diff=(!a)?1:(!b)?-1:cJSONUtils_strcasecmp(a->string,b->string);
if (!diff)
{
char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(a->string)+2);
cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),a->string);
cJSONUtils_CompareToPatch(patches,newpath,a,b);
free(newpath);
a=a->next;
b=b->next;
}
else if (diff<0) {cJSONUtils_GeneratePatch(patches,"remove",path,a->string,0); a=a->next;}
else {cJSONUtils_GeneratePatch(patches,"add",path,b->string,b); b=b->next;}
}
return;
}
default: break;
}
}
cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to)
{
cJSON *patches=cJSON_CreateArray();
cJSONUtils_CompareToPatch(patches,"",from,to);
return patches;
}
static cJSON *cJSONUtils_SortList(cJSON *list)
{
cJSON *first=list,*second=list,*ptr=list;
if (!list || !list->next) return list; /* One entry is sorted already. */
while (ptr && ptr->next && cJSONUtils_strcasecmp(ptr->string,ptr->next->string)<0) ptr=ptr->next; /* Test for list sorted. */
if (!ptr || !ptr->next) return list; /* Leave sorted lists unmodified. */
ptr=list;
while (ptr) {second=second->next;ptr=ptr->next;if (ptr) ptr=ptr->next;} /* Walk two pointers to find the middle. */
if (second && second->prev) second->prev->next=0; /* Split the lists */
first=cJSONUtils_SortList(first); /* Recursively sort the sub-lists. */
second=cJSONUtils_SortList(second);
list=ptr=0;
while (first && second) /* Merge the sub-lists */
{
if (cJSONUtils_strcasecmp(first->string,second->string)<0)
{
if (!list) list=ptr=first;
else {ptr->next=first;first->prev=ptr;ptr=first;}
first=first->next;
}
else
{
if (!list) list=ptr=second;
else {ptr->next=second;second->prev=ptr;ptr=second;}
second=second->next;
}
}
if (first) { if (!list) return first; ptr->next=first; first->prev=ptr; } /* Append any tails. */
if (second) { if (!list) return second; ptr->next=second; second->prev=ptr; }
return list;
}
void cJSONUtils_SortObject(cJSON *object) {object->child=cJSONUtils_SortList(object->child);}

View File

@ -0,0 +1,26 @@
#include "cJSON.h"
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
cJSON *cJSONUtils_GetPointer(cJSON *object,const char *pointer);
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to);
void cJSONUtils_AddPatchToArray(cJSON *array,const char *op,const char *path,cJSON *val); /* Utility for generating patch array entries. */
int cJSONUtils_ApplyPatches(cJSON *object,cJSON *patches); /* Returns 0 for success. */
/*
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
//{
// cJSON *modme=cJSON_Duplicate(*object,1);
// int error=cJSONUtils_ApplyPatches(modme,patches);
// if (!error) {cJSON_Delete(*object);*object=modme;}
// else cJSON_Delete(modme);
// return error;
//}
// Code not added to library since this strategy is a LOT slower.
*/
char *cJSONUtils_FindPointerFromObjectTo(cJSON *object,cJSON *target); /* Given a root object and a target object, construct a pointer from one to the other. */
void cJSONUtils_SortObject(cJSON *object); /* Sorts the members of the object into alphabetical order. */

View File

@ -587,9 +587,14 @@ static int isowavGetSoundBuffer(short* /*buffer*/, int /*samples*/)
return 0;
}
static INT32 isowavScan(INT32 nAction, INT32 *pnMin)
{
return 0;
}
static int isowavGetSettings(InterfaceInfo* /*pInfo*/)
{
return 0;
}
struct CDEmuDo isowavDo = { isowavExit, isowavInit, isowavStop, isowavPlay, isowavLoadSector, isowavReadTOC, isowavReadQChannel, isowavGetSoundBuffer, isowavGetSettings, _T("cue/iso/wav CD emulation") };
struct CDEmuDo isowavDo = { isowavExit, isowavInit, isowavStop, isowavPlay, isowavLoadSector, isowavReadTOC, isowavReadQChannel, isowavGetSoundBuffer, isowavScan, isowavGetSettings, _T("cue/iso/wav CD emulation") };

View File

@ -0,0 +1,688 @@
#include <SDL/SDL.h>
#include <unistd.h>
#include <sys/time.h>
#include "burner.h"
#include "inp_sdl_keys.h"
extern "C" {
#include "inp_udev.h"
#include "cJSON.h"
}
int InputFindCode(const char *keystring);
// Note that these constants are tied to the JOY_ macros!
#define MAX_JOYSTICKS 8
#define MAX_JOY_BUTTONS 28
#define FREEPLAY_HACK_COIN_DURATION_MS 1e3 / 8
//#define DEBUG_INPUT
int nKioskTimeout = 0;
int nEnableFreeplayHack = 0;
static struct timeval lastInputEvent;
static uint64_t startPressUsec[4];
static unsigned int joyButtonStates[MAX_JOYSTICKS];
static int *joyLookupTable = NULL;
static int keyLookupTable[512];
static int mouseScanned = 0;
static int inputEventOccurred = 1;
static void scanKeyboard();
static void scanJoysticks();
static void scanMouse();
static void resetJoystickMap();
static bool usesStreetFighterLayout();
static int checkMouseState(unsigned int nSubCode);
static void handleFreeplayHack();
#define JOY_DIR_LEFT 0x00
#define JOY_DIR_RIGHT 0x01
#define JOY_DIR_UP 0x02
#define JOY_DIR_DOWN 0x03
#define JOY_MAP_DIR(joy,dir) ((((joy)&0xff)<<8)|((dir)&0x3))
#define JOY_MAP_BUTTON(joy,button) ((((joy)&0xff)<<8)|(((button)+4)&0x1f))
#define JOY_IS_DOWN(value) (joyButtonStates[((value)>>8)&0x7]&(1<<((value)&0xff)))
#define JOY_CLEAR(value) joyButtonStates[((value)>>8)&0x7]&=~(1<<((value)&0xff))
#define KEY_IS_DOWN(key) keyState[(key)]
#define JOY_DEADZONE 0x4000
static unsigned char* keyState = NULL;
static struct {
unsigned char buttons;
int xdelta;
int ydelta;
} mouseState;
static char* globFile(const char *path);
///
extern int nExitEmulator;
static int nInitedSubsytems = 0;
static SDL_Joystick* JoyList[MAX_JOYSTICKS];
static int nJoystickCount = 0; // Number of joysticks connected to this machine
static int piInputExit()
{
// Close all joysticks
for (int i = 0; i < MAX_JOYSTICKS; i++) {
if (JoyList[i]) {
SDL_JoystickClose(JoyList[i]);
JoyList[i] = NULL;
}
}
free(joyLookupTable);
joyLookupTable = NULL;
nJoystickCount = 0;
if (!(nInitedSubsytems & SDL_INIT_JOYSTICK)) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
nInitedSubsytems = 0;
phl_udev_shutdown();
return 0;
}
static int piInputInit()
{
piInputExit();
// Allocate memory for the lookup table
if ((joyLookupTable = (int *)malloc(0x8000 * sizeof(int))) == NULL) {
return 1;
}
memset(&JoyList, 0, sizeof(JoyList));
nInitedSubsytems = SDL_WasInit(SDL_INIT_JOYSTICK);
gettimeofday(&lastInputEvent, NULL);
phl_udev_init();
if (!(nInitedSubsytems & SDL_INIT_JOYSTICK)) {
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
}
// Set up the joysticks
nJoystickCount = SDL_NumJoysticks();
for (int i = 0; i < nJoystickCount; i++) {
JoyList[i] = SDL_JoystickOpen(i);
}
SDL_JoystickEventState(SDL_IGNORE);
resetJoystickMap();
return 0;
}
static int piInputStart()
{
// Update SDL event queue
SDL_PumpEvents();
scanJoysticks();
scanKeyboard();
struct timeval now;
gettimeofday(&now, NULL);
if (nEnableFreeplayHack) {
for (int i = 0; i < 4; i++) {
if (!JOY_IS_DOWN(joyLookupTable[FBK_1 + i]) && !KEY_IS_DOWN(keyLookupTable[FBK_1 + i])) {
startPressUsec[i] = 0;
} else if (startPressUsec[i] == 0) {
startPressUsec[i] = now.tv_sec * 1e3 + now.tv_usec / 1e3;
}
}
}
// Mouse not read this frame
mouseScanned = 0;
if (nKioskTimeout > 0) {
if (inputEventOccurred) {
lastInputEvent = now;
inputEventOccurred = 0;
} else if (now.tv_sec - lastInputEvent.tv_sec > nKioskTimeout) {
nExitEmulator = 2;
fprintf(stderr, "Kiosk mode - %ds timeout exceeded\n", nKioskTimeout);
}
}
return 0;
}
// player - 0-4
static int handleFreeplayHack(int player, int code)
{
if (startPressUsec[player] != 0) {
struct timeval now;
gettimeofday(&now, NULL);
uint64_t now_usec = now.tv_sec * 1e3 + now.tv_usec / 1e3;
uint64_t diff = now_usec - startPressUsec[player];
if (diff < FREEPLAY_HACK_COIN_DURATION_MS) {
if (code == FBK_5 + player) {
return 1;
}
} else {
if (code == FBK_1 + player) {
return 1;
}
}
}
return 0;
}
static int piInputState(int nCode)
{
if (nCode < 0) {
return 0;
}
int player = -1;
if (nCode == FBK_1 || nCode == FBK_2 || nCode == FBK_3 || nCode == FBK_4) {
player = nCode - FBK_1;
} else if (nCode == FBK_5 || nCode == FBK_6 || nCode == FBK_7 || nCode == FBK_8) {
player = nCode - FBK_5;
}
if (nCode < 0x100) {
int mapped = keyLookupTable[nCode];
if (nEnableFreeplayHack && player != -1) {
if (handleFreeplayHack(player, nCode)) {
return 1;
}
}
if (KEY_IS_DOWN(mapped)) {
inputEventOccurred = 1;
return 1;
}
}
if (/* nCode >= 0x4000 && */ nCode < 0x8000) {
int mapped = joyLookupTable[nCode];
if (mapped != -1) {
if (nEnableFreeplayHack && player != -1) {
handleFreeplayHack(player, nCode);
}
if (JOY_IS_DOWN(mapped)) {
JOY_CLEAR(mapped);
return 1;
}
}
}
if (nCode >= 0x8000 && nCode < 0xC000) {
// Codes 8000-C000 = Mouse
if ((nCode - 0x8000) >> 8) {
// Only the system mouse is supported by SDL
return 0;
}
if (!mouseScanned) {
scanMouse();
mouseScanned = 1;
}
return checkMouseState(nCode & 0xFF);
}
return 0;
}
// Check a subcode (the 80xx bit in 8001, 8102 etc) for a mouse input code
static int checkMouseState(unsigned int nSubCode)
{
switch (nSubCode & 0x7F) {
case 0: return (mouseState.buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;
case 1: return (mouseState.buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
case 2: return (mouseState.buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
}
return 0;
}
static void scanMouse()
{
mouseState.buttons = SDL_GetRelativeMouseState(&(mouseState.xdelta),
&(mouseState.ydelta));
}
static void scanKeyboard()
{
static int screenshotDown = 0;
static Uint8 emptyStates[512] = { 0 };
if ((keyState = SDL_GetKeyState(NULL)) == NULL) {
keyState = emptyStates;
}
if (keyState[SDLK_ESCAPE]) {
nExitEmulator = 1;
}
if (!screenshotDown && keyState[SDLK_F10]) {
MakeScreenShot();
}
screenshotDown = keyState[SDLK_F10];
}
static void scanJoysticks()
{
SDL_JoystickUpdate();
int joyCount = nJoystickCount;
if (joyCount > MAX_JOYSTICKS) {
joyCount = MAX_JOYSTICKS;
}
#ifdef DEBUG_INPUT
static unsigned int oldButtonStates[MAX_JOYSTICKS];
#endif
for (int joy = 0; joy < joyCount; joy++) {
joyButtonStates[joy] = 0;
SDL_Joystick *joystick = JoyList[joy];
int xPos = SDL_JoystickGetAxis(joystick, 0);
int yPos = SDL_JoystickGetAxis(joystick, 1);
// Directions
int dirStates[] = {
(xPos < -JOY_DEADZONE), // left
(xPos > JOY_DEADZONE), // right
(yPos < -JOY_DEADZONE), // up
(yPos > JOY_DEADZONE), // down
};
for (int i = 0; i < 4; i++) {
joyButtonStates[joy] |= (dirStates[i] << i);
if (dirStates[i] && joyLookupTable[FBK_F12] == JOY_MAP_DIR(joy, i)) {
nExitEmulator = 1;
return;
}
}
// Buttons
int buttonCount = SDL_JoystickNumButtons(joystick);
if (buttonCount > MAX_JOY_BUTTONS) {
buttonCount = MAX_JOY_BUTTONS;
}
for (int button = 0, shift = 4; button < buttonCount; button++, shift++) {
int state = SDL_JoystickGetButton(joystick, button);
joyButtonStates[joy] |= ((state & 1) << shift);
if (state && joyLookupTable[FBK_F12] == JOY_MAP_BUTTON(joy, button)) {
nExitEmulator = 1;
return;
}
}
if (joyButtonStates[joy] != 0) {
inputEventOccurred = 1;
}
#ifdef DEBUG_INPUT
if (oldButtonStates[joy] != joyButtonStates[joy]) {
static char temp[33] = {'\0'};
char *ch = &temp[buttonCount+4]; //32-(buttonCount+4)];
for (int i = buttonCount + 4; i >= 0; i--,ch--) {
*ch = ((joyButtonStates[joy] >> i) & 1) + '0';
}
fprintf(stderr, "J%d: %s\n", joy + 1, ch + 1);
oldButtonStates[joy] = joyButtonStates[joy];
}
#endif
}
}
static bool usesStreetFighterLayout()
{
int fireButtons = 0;
struct BurnInputInfo bii;
for (UINT32 i = 0; i < 0x1000; i++) {
bii.szName = NULL;
if (BurnDrvGetInputInfo(&bii,i)) {
break;
}
BurnDrvGetInputInfo(&bii, i);
if (bii.szName == NULL) {
bii.szName = "";
}
bool bPlayerInInfo = (toupper(bii.szInfo[0]) == 'P' && bii.szInfo[1] >= '1' && bii.szInfo[1] <= '4'); // Because some of the older drivers don't use the standard input naming.
bool bPlayerInName = (bii.szName[0] == 'P' && bii.szName[1] >= '1' && bii.szName[1] <= '4');
if (bPlayerInInfo || bPlayerInName) {
INT32 nPlayer = 0;
if (bPlayerInName) {
nPlayer = bii.szName[1] - '1';
}
if (bPlayerInInfo && nPlayer == 0) {
nPlayer = bii.szInfo[1] - '1';
}
if (nPlayer == 0) {
if (strncmp(" fire", bii.szInfo + 2, 5) == 0) {
fireButtons++;
}
}
}
}
int hardwareMask = BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK;
return fireButtons >= 6 &&
(hardwareMask == HARDWARE_CAPCOM_CPS1 ||
hardwareMask == HARDWARE_CAPCOM_CPS2 ||
hardwareMask == HARDWARE_CAPCOM_CPS3);
}
struct JoyConfig {
char **labels;
int labelCount;
};
static struct JoyConfig* createJoyConfig(cJSON *root)
{
struct JoyConfig *jc = (struct JoyConfig *)malloc(sizeof(struct JoyConfig));
if (jc) {
jc->labels = NULL;
jc->labelCount = 0;
cJSON *labelParent = cJSON_GetObjectItem(root, "labels");
cJSON *labelNode;
if (labelParent) {
labelNode = labelParent->child;
while (labelNode) {
if (strncmp(labelNode->string, "button", 6) == 0) {
int index = atoi(labelNode->string + 6);
if (index > 0 && index <= MAX_JOY_BUTTONS && index > jc->labelCount) {
jc->labelCount = index;
}
}
labelNode = labelNode->next;
}
if (jc->labelCount > 0) {
jc->labels = (char **)calloc(jc->labelCount, sizeof(char *));
if (jc->labels) {
labelNode = labelParent->child;
while (labelNode) {
int index = atoi(labelNode->string + 6) - 1;
if (index >= 0 && index < MAX_JOY_BUTTONS) {
jc->labels[index] = strdup(labelNode->valuestring);
}
labelNode = labelNode->next;
}
}
}
}
}
return jc;
}
static void dumpJoyConfig(struct JoyConfig *jc)
{
for (int i = 0; i < jc->labelCount; i++) {
fprintf(stderr, "labels[%d]='%s'\n", i, jc->labels[i]);
}
}
static void destroyJoyConfig(struct JoyConfig *jc)
{
for (int i = 0; i < jc->labelCount; i++) {
free(jc->labels[i]);
}
free(jc->labels);
jc->labels = NULL;
jc->labelCount = 0;
free(jc);
}
static int findButton(struct JoyConfig *jc, const char *label)
{
for (int i = 0; i < jc->labelCount; i++) {
if (jc->labels[i] && strcasecmp(jc->labels[i], label) == 0) {
return i;
}
}
if (strncmp(label, "button", 6) == 0) {
int index = atoi(label + 6) - 1;
if (index >= 0 && index < MAX_JOY_BUTTONS) {
return index;
}
}
return -1;
}
static void parseButtons(int player, struct JoyConfig *jc, cJSON *json)
{
cJSON *node = json->child;
char temp[100];
while (node) {
int index = findButton(jc, node->string);
if (index > -1) {
int code;
if ((code = InputFindCode(node->valuestring)) != -1) {
joyLookupTable[code] = JOY_MAP_BUTTON(player, index);
} else {
// No literal match - try prepending player id
snprintf(temp, 99, "P%d %s", player + 1, node->valuestring);
if ((code = InputFindCode(temp)) != -1) {
joyLookupTable[code] = JOY_MAP_BUTTON(player, index);
}
}
}
node = node->next;
}
}
static void parsePlayerConfig(int player, struct JoyConfig *jc, cJSON *json)
{
cJSON *node;
int code;
const char *dirnames[] = { "up","down","left","right" };
int dirconsts[] = { JOY_DIR_UP,JOY_DIR_DOWN,JOY_DIR_LEFT,JOY_DIR_RIGHT };
char temp[100];
for (int i = 0; i < 4; i++) {
if ((node = cJSON_GetObjectItem(json, dirnames[i]))) {
if ((code = InputFindCode(node->valuestring)) != -1) {
joyLookupTable[code] = JOY_MAP_DIR(player, dirconsts[i]);
} else {
// No literal match - try prepending player id (e.g. P1, etc)
snprintf(temp, 99, "P%d %s", player + 1, node->valuestring);
if ((code = InputFindCode(temp)) != -1) {
joyLookupTable[code] = JOY_MAP_DIR(player, dirconsts[i]);
}
}
}
}
parseButtons(player, jc, json);
if (usesStreetFighterLayout()) {
cJSON *sf = cJSON_GetObjectItem(json, "sfLayout");
if (sf) {
parseButtons(player, jc, sf);
}
}
}
static int setupDefaults(int pindex)
{
int fbDirs[4];
int fbButtons[6]; // absolute max
int buttonCount = 0;
if (pindex == 0) {
int i = 0;
fbDirs[i++] = FBK_UPARROW;
fbDirs[i++] = FBK_LEFTARROW;
fbDirs[i++] = FBK_RIGHTARROW;
fbDirs[i++] = FBK_DOWNARROW;
if (usesStreetFighterLayout()) {
fbButtons[buttonCount++] = FBK_A;
fbButtons[buttonCount++] = FBK_S;
fbButtons[buttonCount++] = FBK_D;
fbButtons[buttonCount++] = FBK_Z;
fbButtons[buttonCount++] = FBK_X;
fbButtons[buttonCount++] = FBK_C;
} else {
fbButtons[buttonCount++] = FBK_A;
fbButtons[buttonCount++] = FBK_S;
fbButtons[buttonCount++] = FBK_D;
fbButtons[buttonCount++] = FBK_Z;
// fbButtons[buttonCount++] = FBK_X;
// fbButtons[buttonCount++] = FBK_C;
// fbButtons[buttonCount++] = FBK_V;
}
} else if (pindex >= 1 && pindex <= 3) {
// P2 to P4
int pmasks[] = { 0x4000, 0x4100, 0x4200 };
int pmask = pmasks[pindex - 1];
int i = 0;
fbDirs[i++] = pmask|0x02;
fbDirs[i++] = pmask|0x00;
fbDirs[i++] = pmask|0x01;
fbDirs[i++] = pmask|0x03;
for (; buttonCount < 6; buttonCount++) {
fbButtons[buttonCount] = pmask|(0x80 + buttonCount);
}
} else {
return 0;
}
// Set direction defaults
int joyDirs[] = { JOY_DIR_UP, JOY_DIR_LEFT, JOY_DIR_RIGHT, JOY_DIR_DOWN };
for (int i = 0; i < 4; i++) {
joyLookupTable[fbDirs[i]] = JOY_MAP_DIR(pindex, joyDirs[i]);
}
// Set button defaults
for (int i = 0; i < buttonCount; i++) {
joyLookupTable[fbButtons[i]] = JOY_MAP_BUTTON(pindex, i);
}
return 1;
}
static int readConfigFile(int pindex, const char *path)
{
int success = 0;
if (pindex >= 0 && pindex <= 3) {
char *pnodes[] = { "joy1", "joy2", "joy3", "joy4" };
char *contents = globFile(path);
if (contents) {
cJSON *root = cJSON_Parse(contents);
if (root) {
struct JoyConfig *jc = createJoyConfig(root);
cJSON *player;
if ((player = cJSON_GetObjectItem(root, "default"))) {
parsePlayerConfig(pindex, jc, player);
}
if ((player = cJSON_GetObjectItem(root, pnodes[pindex]))) {
parsePlayerConfig(pindex, jc, player);
}
destroyJoyConfig(jc);
cJSON_Delete(root);
success = 1;
}
free(contents);
}
}
return success;
}
static void resetJoystickMap()
{
for (int i = 0; i < 0x8000; i++) {
joyLookupTable[i] = -1;
}
for (int i = 0; i < 512; i++) {
int code = SDLtoFBK[i];
keyLookupTable[code] = (code > 0) ? i : -1;
}
for (int i = 0, n = phl_udev_joy_count(); i < n; i++) {
const char *devId = phl_udev_joy_id(i);
fprintf(stderr, "Detected \"%s\" (USB id %s) in port %d\n",
phl_udev_joy_name(i), devId, i + 1);
// Set the defaults
setupDefaults(i);
// Try loading a config file
if (devId != NULL) {
char path[100];
snprintf(path, 99, "joyconfig/%s.joy", devId);
char *colon = strchr(path, ':');
if (colon) *colon = '-';
if (access(path, F_OK) != -1) {
fprintf(stderr, " * Found configuration file \"%s\"\n", path);
if (!readConfigFile(i, path)) {
fprintf(stderr, "Error reading configuration file - check format\n");
}
} else {
fprintf(stderr, " * No configuration file at \"%s\" - will use defaults\n", path);
}
}
}
}
static char* globFile(const char *path)
{
char *contents = NULL;
FILE *file = fopen(path,"r");
if (file) {
// Determine size
fseek(file, 0L, SEEK_END);
long size = ftell(file);
rewind(file);
// Allocate memory
contents = (char *)malloc(size + 1);
if (contents) {
contents[size] = '\0';
// Read contents
if (fread(contents, size, 1, file) != 1) {
free(contents);
contents = NULL;
}
}
fclose(file);
}
return contents;
}
struct InputInOut InputInOutSDL = { piInputInit, piInputExit, NULL, piInputStart, piInputState, NULL, NULL, NULL, NULL, NULL, _T("Raspberry Pi input") };

View File

@ -0,0 +1,102 @@
#include <cstddef>
#include "string.h"
#include "inp_keys.h"
struct Input {
const char *name;
const int code;
};
#define P2_JOY 0x4000
#define P3_JOY 0x4100
#define P4_JOY 0x4200
static const Input allInputs[] = {
// Generic
{ "P1 START", FBK_1, },
{ "P2 START", FBK_2, },
{ "P1 COIN", FBK_5, },
{ "P2 COIN", FBK_6, },
{ "TEST", FBK_F2, },
{ "SERVICE", FBK_9, },
{ "SELECT1", FBK_3, },
{ "SELECT2", FBK_4, },
{ "RESET", FBK_F3, },
{ "QUIT", FBK_ESCAPE, },
// Keyboard
{ "P1 UP", FBK_UPARROW, },
{ "P1 LEFT", FBK_LEFTARROW, },
{ "P1 RIGHT", FBK_RIGHTARROW, },
{ "P1 DOWN", FBK_DOWNARROW, },
{ "P1 JAB", FBK_A, },
{ "P1 STRONG", FBK_S, },
{ "P1 FIERCE", FBK_D, },
{ "P1 SHORT", FBK_Z, },
{ "P1 FORWARD", FBK_X, },
{ "P1 ROUNDHOUSE", FBK_C, },
{ "P1 BUTTON 1", FBK_Z, },
{ "P1 BUTTON 2", FBK_X, },
{ "P1 BUTTON 3", FBK_C, },
{ "P1 BUTTON 4", FBK_V, },
// Joystick
{ "P2 UP", P2_JOY | 0x02, },
{ "P2 LEFT", P2_JOY | 0x00, },
{ "P2 RIGHT", P2_JOY | 0x01, },
{ "P2 DOWN", P2_JOY | 0x03, },
{ "P2 BUTTON 1", P2_JOY | 0x80, },
{ "P2 BUTTON 2", P2_JOY | 0x81, },
{ "P2 BUTTON 3", P2_JOY | 0x82, },
{ "P2 BUTTON 4", P2_JOY | 0x83, },
{ "P2 JAB", P2_JOY | 0x80, },
{ "P2 STRONG", P2_JOY | 0x81, },
{ "P2 FIERCE", P2_JOY | 0x82, },
{ "P2 SHORT", P2_JOY | 0x83, },
{ "P2 FORWARD", P2_JOY | 0x84, },
{ "P2 ROUNDHOUSE", P2_JOY | 0x85, },
{ "P3 UP", P3_JOY | 0x02, },
{ "P3 LEFT", P3_JOY | 0x00, },
{ "P3 RIGHT", P3_JOY | 0x01, },
{ "P3 DOWN", P3_JOY | 0x03, },
{ "P3 BUTTON 1", P3_JOY | 0x80, },
{ "P3 BUTTON 2", P3_JOY | 0x81, },
{ "P3 BUTTON 3", P3_JOY | 0x82, },
{ "P3 BUTTON 4", P3_JOY | 0x83, },
{ "P3 JAB", P3_JOY | 0x80, },
{ "P3 STRONG", P3_JOY | 0x81, },
{ "P3 FIERCE", P3_JOY | 0x82, },
{ "P3 SHORT", P3_JOY | 0x83, },
{ "P3 FORWARD", P3_JOY | 0x84, },
{ "P3 ROUNDHOUSE", P3_JOY | 0x85, },
{ "P4 UP", P4_JOY | 0x02, },
{ "P4 LEFT", P4_JOY | 0x00, },
{ "P4 RIGHT", P4_JOY | 0x01, },
{ "P4 DOWN", P4_JOY | 0x03, },
{ "P4 BUTTON 1", P4_JOY | 0x80, },
{ "P4 BUTTON 2", P4_JOY | 0x81, },
{ "P4 BUTTON 3", P4_JOY | 0x82, },
{ "P4 BUTTON 4", P4_JOY | 0x83, },
{ "P4 JAB", P4_JOY | 0x80, },
{ "P4 STRONG", P4_JOY | 0x81, },
{ "P4 FIERCE", P4_JOY | 0x82, },
{ "P4 SHORT", P4_JOY | 0x83, },
{ "P4 FORWARD", P4_JOY | 0x84, },
{ "P4 ROUNDHOUSE", P4_JOY | 0x85, },
{ NULL, 0, },
};
int InputFindCode(const char *keystring)
{
for (const struct Input *input = allInputs; input->name != NULL; input++) {
if (strcasecmp(input->name, keystring) == 0) {
return input->code;
}
}
return -1;
}

View File

@ -0,0 +1,405 @@
/**
** Copyright (C) 2015 Akop Karapetyan
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**/
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include "inp_udev.h"
#define MAX_DEVICES 10
// #define DUMP_DEVICES
struct USBDevice {
char *path;
char *vendorId;
char *productId;
char *mfr;
char *product;
};
static pthread_t monthread;
static int stopMonitor = 0;
static int initted = 0;
static struct udev *udev = NULL;
static struct udev_monitor *mon;
static void* monitor(void *arg);
static struct USBDevice* create_usb_device(struct udev_device *dev);
static void destroy_usb_device(struct USBDevice *usbDev);
static const char* device_id(int index,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex);
static const char* device_product(int index,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex);
static void add_device(struct udev_device *dev,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex);
static void remove_device(struct udev_device *dev,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex);
static void clear_devices(struct USBDevice *devices[], int *deviceCount,
pthread_mutex_t *mutex);
static void clear_all_devices();
static void scan_devices();
static void dump_all_devices();
static void dump_devices(struct USBDevice *devices[], const char *desc,
int *deviceCount, pthread_mutex_t *mutex);
static int joystickCount = 0;
static int mouseCount = 0;
static struct USBDevice *joysticks[MAX_DEVICES];
static struct USBDevice *mice[MAX_DEVICES];
static pthread_mutex_t joystickLock;
static pthread_mutex_t mouseLock;
// Based on
// http://www.signal11.us/oss/udev/udev_example.c
int phl_udev_init()
{
if (!initted) {
if (!(udev = udev_new())) {
return 0;
}
if (pthread_mutex_init(&joystickLock, NULL) != 0) {
udev_unref(udev);
return 0;
}
if (pthread_mutex_init(&mouseLock, NULL) != 0) {
pthread_mutex_destroy(&joystickLock);
udev_unref(udev);
return 0;
}
mon = udev_monitor_new_from_netlink(udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
udev_monitor_enable_receiving(mon);
scan_devices();
if (pthread_create(&monthread, NULL, monitor, NULL) != 0) {
pthread_mutex_destroy(&mouseLock);
pthread_mutex_destroy(&joystickLock);
udev_unref(udev);
return 0;
}
fprintf(stderr, "udev initialized\n");
initted = 1;
}
return 1;
}
int phl_udev_shutdown()
{
if (initted) {
stopMonitor = 1;
pthread_join(monthread, NULL);
clear_all_devices();
fprintf(stderr, "udev shut down\n");
udev_unref(udev);
pthread_mutex_destroy(&joystickLock);
pthread_mutex_destroy(&mouseLock);
initted = 0;
}
return 1;
}
int phl_udev_joy_count()
{
return joystickCount;
}
int phl_udev_mouse_count()
{
return mouseCount;
}
const char* phl_udev_joy_id(int index)
{
return device_id(index, joysticks, &joystickCount, &joystickLock);
}
const char* phl_udev_joy_name(int index)
{
return device_product(index, joysticks, &joystickCount, &joystickLock);
}
static void scan_devices()
{
fprintf(stderr, "Scanning devices...\n");
clear_all_devices();
struct udev_enumerate *uenum;
struct udev_list_entry *devices, *devEntry;
uenum = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(uenum, "input");
udev_enumerate_scan_devices(uenum);
devices = udev_enumerate_get_list_entry(uenum);
udev_list_entry_foreach(devEntry, devices) {
const char *path = udev_list_entry_get_name(devEntry);
struct udev_device *dev = udev_device_new_from_syspath(udev, path);
const char *sysname = udev_device_get_sysname(dev);
if (strncmp(sysname, "mouse", 5) == 0) {
add_device(dev, mice, &mouseCount, &mouseLock);
} else if (strncmp(sysname, "js", 2) == 0) {
add_device(dev, joysticks, &joystickCount, &joystickLock);
}
udev_device_unref(dev);
};
udev_enumerate_unref(uenum);
}
static void* monitor(void *arg)
{
fprintf(stderr, "udev monitor starting\n");
int monfd = udev_monitor_get_fd(mon);
struct udev_device *dev;
fd_set fds;
struct timeval tv;
int ret;
while (!stopMonitor) {
FD_ZERO(&fds);
FD_SET(monfd, &fds);
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select(monfd + 1, &fds, NULL, NULL, &tv);
if (ret > 0 && FD_ISSET(monfd, &fds)) {
// Make the call to receive the device.
// select() ensured that this will not block.
dev = udev_monitor_receive_device(mon);
if (dev) {
const char *sysname = udev_device_get_sysname(dev);
const char *action = udev_device_get_action(dev);
if (strncmp(sysname, "mouse", 5) == 0) {
if (strncmp(action, "add", 3) == 0) {
fprintf(stderr, "+ mouse\n");
add_device(dev, mice, &mouseCount, &mouseLock);
} else if (strncmp(action, "remove", 6) == 0) {
fprintf(stderr, "- mouse\n");
remove_device(dev, mice, &mouseCount, &mouseLock);
}
#ifdef DUMP_DEVICES
dump_all_devices();
#endif
} else if (strncmp(sysname, "js", 2) == 0) {
if (strncmp(action, "add", 3) == 0) {
fprintf(stderr, "+ joystick\n");
add_device(dev, joysticks, &joystickCount, &joystickLock);
} else if (strncmp(action, "remove", 6) == 0) {
fprintf(stderr, "- joystick\n");
remove_device(dev, joysticks, &joystickCount, &joystickLock);
}
#ifdef DUMP_DEVICES
dump_all_devices();
#endif
}
udev_device_unref(dev);
}
}
usleep(250*1000);
}
fprintf(stderr, "udev monitor exiting\n");
return NULL;
}
#ifdef TEST_MAIN
int main(int argc, char* argv[])
{
udevInit();
fprintf(stderr, "Starting...\n");
char *my_string;
int nbytes = 100;
getline(&my_string, &nbytes, stdin);
dump_all_devices();
fprintf(stderr, "Ending\n");
udevShutdown();
return 0;
}
#endif
static struct USBDevice* create_usb_device(struct udev_device *dev)
{
const char *path = udev_device_get_syspath(dev);
dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
struct USBDevice *usbDev = NULL;
if (dev != NULL) {
usbDev = (struct USBDevice *)calloc(1, sizeof(struct USBDevice));
if (usbDev != NULL) {
usbDev->path = strdup(path);
const char *p;
if ((p = udev_device_get_sysattr_value(dev, "idVendor")) != NULL) {
usbDev->vendorId = strdup(p);
}
if ((p = udev_device_get_sysattr_value(dev, "idProduct")) != NULL) {
usbDev->productId = strdup(p);
}
if ((p = udev_device_get_sysattr_value(dev, "manufacturer")) != NULL) {
usbDev->mfr = strdup(p);
}
if ((p = udev_device_get_sysattr_value(dev, "product")) != NULL) {
usbDev->product = strdup(p);
}
}
}
return usbDev;
}
static void destroy_usb_device(struct USBDevice *usbDev)
{
free(usbDev->vendorId);
free(usbDev->productId);
free(usbDev->mfr);
free(usbDev->product);
free(usbDev);
}
static const char* device_id(int index,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex)
{
char *result = NULL;
static char temp[100];
pthread_mutex_lock(mutex);
if (index < *deviceCount) {
snprintf(temp, 99, "%s:%s",
devices[index]->vendorId, devices[index]->productId);
result = temp;
}
pthread_mutex_unlock(mutex);
return result;
}
static const char* device_product(int index,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex)
{
char *result = NULL;
static char temp[100];
pthread_mutex_lock(mutex);
if (index < *deviceCount) {
strncpy(temp, devices[index]->product, 99);
result = temp;
}
pthread_mutex_unlock(mutex);
return result;
}
static void add_device(struct udev_device *dev,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex)
{
pthread_mutex_lock(mutex);
if (*deviceCount + 1 < MAX_DEVICES) {
struct USBDevice *usbDev = create_usb_device(dev);
if (usbDev != NULL) {
devices[(*deviceCount)++] = usbDev;
}
}
pthread_mutex_unlock(mutex);
}
static void remove_device(struct udev_device *dev,
struct USBDevice *devices[], int *deviceCount, pthread_mutex_t *mutex)
{
const char *path = udev_device_get_syspath(dev);
int i, j;
pthread_mutex_lock(mutex);
for (i = 0; i < *deviceCount; i++) {
if (strcmp(path, devices[i]->path) == 0) {
// Destroy the removed item
destroy_usb_device(devices[i]);
// Move the items back one slot
for (j = i + 1; j < *deviceCount; j++) {
devices[j - 1] = devices[j];
}
(*deviceCount)--;
break;
}
}
pthread_mutex_unlock(mutex);
}
static void clear_devices(struct USBDevice *devices[], int *deviceCount,
pthread_mutex_t *mutex)
{
int i;
pthread_mutex_lock(mutex);
for (i = 0; i < *deviceCount; i++) {
destroy_usb_device(devices[i]);
}
*deviceCount = 0;
pthread_mutex_unlock(mutex);
}
static void clear_all_devices()
{
clear_devices(joysticks, &joystickCount, &joystickLock);
}
static void dump_devices(struct USBDevice *devices[], const char *desc,
int *deviceCount, pthread_mutex_t *mutex)
{
int i;
pthread_mutex_lock(mutex);
for (i = 0; i < *deviceCount; i++) {
fprintf(stderr, "Joy %d: %s:%s %s (%s)\n", i,
devices[i]->vendorId, devices[i]->productId,
devices[i]->product,
devices[i]->path);
}
pthread_mutex_unlock(mutex);
fprintf(stderr, "%d %s\n", *deviceCount, desc);
}
static void dump_all_devices()
{
dump_devices(joysticks, "joystick(s)", &joystickCount, &joystickLock);
dump_devices(mice, "m(ous|ic)e", &mouseCount, &mouseLock);
}

View File

@ -0,0 +1,29 @@
/**
** Copyright (C) 2015 Akop Karapetyan
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
**/
#ifndef PHL_UDEV_H
#define PHL_UDEV_H
int phl_udev_init();
int phl_udev_shutdown();
int phl_udev_joy_count();
int phl_udev_mouse_count();
const char* phl_udev_joy_name(int index);
const char* phl_udev_joy_id(int index);
#endif // PHL_UDEV_H