他人の空似自作物置場

osaisen.zip/osaisen.c

#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

//#define DEBUG

enum{
	HTTP,
	FTP
};

typedef struct url{
	int prot;
	char host[64];
	char path[1024];
	DWORD addr;
	int port;
}URL;

typedef struct list{
	void *p;
	struct list *next;
}LIST;

typedef struct id_list{
	char id[10];
	short num;
}ID_LIST;

char BoardURL[1024] = "http://jbbs.livedoor.jp/computer/41116/";
char ThreName[256] = "";
int matubi = 0;
int OtoZero = 0;

LIST *head = NULL;

URL *spliturl(char *url);


//free忘れ対策、終了時にfreeする
//(OSに任せても大丈夫?)
void freelist_free(void){
	LIST *a;

	while(head != NULL){
		a = head;
		head = head->next;
#ifdef DEBUG
		printf("endfree is %d\n",a->p);
#endif
		free(a->p);
		free(a);
	}
}

void end_free(void *p){
	LIST *a;

	if(head == NULL){
		atexit(freelist_free);

		head = (LIST *)malloc(sizeof(LIST));
		a = head;
	} else {
		a = head;
		while(a->next != NULL)a = a->next;
		a->next = (LIST *)malloc(sizeof(LIST));
		a = a->next;
	}
	a->next = NULL;
	a->p = p;
#ifdef DEBUG
	printf("free regist is %d\n",a->p);
#endif
}

void free2(void *p){
	LIST *a,*b=NULL;

	a = head;
	while(a != NULL){
		if(a->p == p){
			if(b != NULL){
				b->next = a->next;
			} else {
				head = a->next;
			}
#ifdef DEBUG
		printf("free2 is %d\n",a->p);
#endif
			free(a->p);
			free(a);
			break;
		}
		b = a;
		a = a->next;
	}
}

//簡易ファイル作成関数
void fileout(char *fn,char *s){
	FILE *fp;

	fp = fopen(fn,"w");
	fwrite(s,sizeof(char),strlen(s),fp);
	fclose(fp);
}

void debugout(char *s){
	static int count = 0;
	char str[16];

	sprintf(str,"debug_%d.log",count++);
	fileout(str,s);
}

//簡易文字列置き換え関数
int ChangeStr(char *str,char s1,char s2){
	int i,count = 0;

	for(i = 0 ; str[i] != '\0' ; i++){
		if(str[i] == s1){
			str[i] = s2;
			count++;
		}
	}

	return count;
}

//デフォルト指定可能版atoi
int atoi2(char *str,int def){
	int i;

	if(!isdigit(str[0]))return def;
	i = atoi(str);
	if(i == 0 && str[0] != '0')return def;

	return i;
}

//指定文字数検索
int countchr(char *str,char s){
	int count = 0;
	char *p = str;

	if(str == NULL)return 0;
	while(*p != '\0'){
		if(*p == s)count++;
		p++;
	}
	return count;
}

//設定読み込み処理
void LoadSetting(void){
	FILE *fp;
	char str[256];

	fp = fopen("setting.ini","r");
	if(fp==NULL)return;

	while(fgets(str,256,fp) != NULL){
		if(!strncmp(str,"//",2) || *str == '\n')continue;
		ChangeStr((char *)&str,'\n','\0');

//if(!strncmp(str,"x=",strlen("x")+1))x=atoi2(&str[strlen("x")],-1)
//if(!strncmp(str,"x=",strlen("x")+1))strcpy(x,&str[strlen("x")])
		if(!strncmp(str,"BoardURL=",strlen("BoardURL")+1))strcpy(BoardURL,&str[strlen("BoardURL")+1]);
		if(!strncmp(str,"ThreName=",strlen("ThreName")+1))strcpy(ThreName,&str[strlen("ThreName")+1]);
		if(!strncmp(str,"matubi=",strlen("matubi")+1))matubi=atoi2(&str[strlen("matubi")],-1);
		if(!strncmp(str,"OtoZero=",strlen("OtoZero")+1))OtoZero=atoi2(&str[strlen("OtoZero")],-1);
	}
	return;
}


void socket_end(void){
	//winsock2の終了処理
	WSACleanup();
}

int socket_init(void){
	WSADATA	wsaData;

	//初期化
	if (WSAStartup(MAKEWORD(2,0), &wsaData)){
		printf("WSAStartup Error\n");
		getchar();
		return 1;
	}

	atexit(socket_end);
	return 0;
}

int inet_aton(const char *cp, struct in_addr *inp){
	unsigned int addr = inet_addr(cp);
	if(addr != INADDR_NONE || strcmp(cp,"255.255.255.255") == 0){
		if(inp)inp->s_addr = addr;
		return 1;
	}
	return 0;
}
DWORD getip(char *dns){
	HOSTENT *host;
	struct in_addr in;

	if(inet_aton(dns,&in)){
		return in.s_addr;
	}
	host = gethostbyname(dns);
	if(host == NULL){
		return -1;
	} else {
		return *((DWORD *)(host->h_addr_list[0]));
	}
}

URL *spliturl(char *url){
	char *s,*e,str[1024];
	URL *ret;

	if(url == NULL)return NULL;
	strcpy(str,url);
	s = strchr(str,':');
	if(s == NULL || strncmp(s,"://",3))return NULL;
	*s = '\0';
	ret = (URL *)malloc(sizeof(URL));
	if(!strcmp(str,"http"))ret->prot = HTTP;
	else if(!strcmp(str,"ftp"))ret->prot = FTP;
	else return NULL;
	s+=3;

	e = strchr(s,':');
	if(e == NULL){
		strcpy(ret->path,"/");
		e = strchr(s,'/');
		if(e != NULL){
			strcpy(ret->path,e);
			*e = '\0';
		}
		strcpy(ret->host,s);
		ret->port = 80;//今はとりあえず80固定
	} else {
		*e = '\0';
		strcpy(ret->host,s);
		s = e+1;
		strcpy(ret->path,"/");
		e = strchr(s,'/');
		if(e != NULL){
			strcpy(ret->path,e);
			*e = '\0';
		}
		ret->port = atoi(s);
	}
	ret->addr = getip(ret->host);

	return ret;
}


void init(void){
	LoadSetting();
	socket_init();
}

int receive(SOCKET s,char* buf,int len){
	int received;
	int tmp;
	received=0;
	while(received<len){
		tmp=recv(s,buf+received,len-received,0);
		if(tmp==SOCKET_ERROR){     /* エラーが発生 */
			return SOCKET_ERROR;
		}
		if(tmp==0){         /* ソケットが切断された */
			return received;
		}
		received+=tmp;
	}
	return received;
}


int recv2(SOCKET sock,char *buf,int size,char *str){
	char *s,i;

	s = buf;
	while(s < buf+size){
		i = recv(sock,s,1,0);
		if(i == 0 || i == SOCKET_ERROR)break;
		if(*s == *str){
			i = recv(sock,s+1,3,0);
			if(i == 3 && strncmp(s,str,strlen(str))){
				s += 4;
				break;
			}
			s += i;
		}
		s++;
	}
	return s-buf;
}

//簡易HTTPGET関数
//問題点:
//	タイムアウトしない(鯖に切断されるまで延々待機の無限ループ)
//	他にも色々
char *get(char *address){
	char *s=NULL,*a,*b,str[1024];
	SOCKET sock;
	URL *url;
	struct sockaddr_in addr;
	int temp,size;

	//ソケットの作成
	sock= socket(AF_INET,SOCK_STREAM,0);
	if(sock == INVALID_SOCKET)return NULL;
	url = spliturl(address);
	if(url == NULL)goto del_sock;

	//ソケットの設定
	addr.sin_family = AF_INET;
	addr.sin_port = htons(url->port);
	addr.sin_addr.S_un.S_addr = url->addr;
	connect(sock,(struct sockaddr *)&addr,sizeof(addr));
	if(sock == SOCKET_ERROR)goto del_url;
	sprintf(str,"GET %s HTTP/1.1\nConnection: close\nHost: %s:%d\r\n\r\n",url->path,url->host,url->port);
	//printf("send\n%s\n",str);
	if(SOCKET_ERROR == send(sock,str,strlen(str)+1,0))goto del_url;

	temp = receive(sock,str,1023);
	str[temp] = '\0';
	a = strstr(str,"\r\n\r\n");
	if(a == NULL)goto del_url;
	*a = '\0';
	if(NULL != strstr(str,"Transfer-Encoding: chunked")){	//ストリーミング受信
		strcpy(str,a+2);
		size = 0;
		while(1){
			if(size == 0){
				if(*str == '\0'){
					temp = receive(sock,str,1023);
					str[temp] = '\0';
				}
				//printf("%s:",str);
				a = strstr(str+2,"\r\n");
				*a = '\0';
				sscanf(str+2,"%x",&size);
				//printf("%d\n",size);
				if(size == 0)break;
				a+=2;
				if(s == NULL){
					s = (char *)malloc(sizeof(char)*(size+1));
					strncpy(s,a,size);
				} else {
					b = s;
					s = (char *)malloc(sizeof(char)*(size+1+strlen(s)));
					strcpy(s,b);
					free(b);
					strncat(s,a,size);
				}
				size-=strlen(a);
			} else {
				if(size < 1023)temp = receive(sock,str,size);
				else temp = receive(sock,str,1023);
				if(temp == 0)break;
				str[temp] = '\0';
				strncat(s,str,size);
				size-=strlen(str);
			}
			if(size < 0)break;
			*str = '\0';
		}
		s[strlen(s)-1] = '\0';
	} else {						//通常受信
		s = (char *)malloc(sizeof(char)*(strlen(a+4)+1));
		strcpy(s,a+4);
		while(1){
			temp = receive(sock,str,1023);
			//printf("%d:%s",temp,str);
			if(temp != SOCKET_ERROR && temp != 0){
				str[temp] = '\0';
				a = (char *)malloc(sizeof(char)*(strlen(s)+1+temp));
				if(a == NULL)break;
				strcpy(a,s);
				strcpy(&(a[strlen(s)]),str);
				free(s);
				s = a;
			} else break;
		}
	}

del_url:
	shutdown(sock,SD_BOTH);
	free(url);

del_sock:
	closesocket(sock);

	if(s != NULL)end_free((void *)s);

	return s;
}

char *strtok2(char *s1, const char *s2){
	static char *p = NULL;

	if(p != s1){
		p = s1;
		return strtok(s1,s2);
	} else return strtok(NULL,s2);
}

int geturl(char *url){
	char temp[1024],*data,*p,*s;
	int ret = 0;
	URL *uri;

	strcpy(temp,BoardURL);
	data = get(strcat(temp,"subject.txt"));
	while( NULL != (p = strtok2(data,"\n")) ){
		if(strstr(p,ThreName) != NULL){
			ChangeStr(p,'.','\0');
			uri = spliturl(BoardURL);
			sprintf(temp,"http://%s/bbs/rawmode.cgi%s%s/",uri->host,uri->path,p);
			free(uri);
			strcpy(url,temp);
			ret = 1;
			break;
		}
	}
	free2(data);
	return ret;
}

ID_LIST *getidlist(char *data){
	char *p,*c;
	ID_LIST *list,*a,*b;
	int size;

	if(data == NULL)return NULL;
	size = countchr(data,'\n')+1;
	list = (ID_LIST *)malloc(sizeof(ID_LIST)*(size+1));
	if(list == NULL)return NULL;
	end_free(list);

	a = list;
	while( NULL != (c = strtok2(data,"\n")) ){
		p = strchr(c,'<');
		*p = '\0';
		a->num = atoi(c);
		p = strrchr(p+1,'>');
		p++;

		b = list;
		while(b < a){
			if(strcmp(p,b->id) == 0)break;
			b++;
		}
		if(a != b){
			//printf("Failed ID:%s\n",p);
			continue;
		}
		strcpy(a->id,p);
		a++;
	}
	a->id[0] = '\0';

	return list;
}

int id2money(ID_LIST *list){
	char *s,a[10];
	int count = 0,flag = 0;

	strcpy(a,list->id);
	if(OtoZero){
		s = a;
		while(s < a+10){
			if(*s == 'o' || *s == 'O')*s = '0';
			s++;
		}
	}
	if(!matubi){
		a[8] = '\0';
	}

	s = a;
	while(s < a+10){
		if(isdigit(*s)){
			if(flag == 0){
				count += atoi(s);
				flag = 1;
			}
		} else {
			if(flag == 1){
				flag = 0;
			}
		}
		s++;
	}
	return count;
}


int main(){
	char *s,url[1024],str[5894];
	ID_LIST *max_p,*list;
	unsigned int temp,sum,max,count,zero;

	init();

	if(matubi == -1 || OtoZero == -1)printf("処理方法を選択してください\n");
	while(matubi == -1){
		printf("末尾(IDの9字目を含める場合は1を、含めないなら0を入力してください\n>");
		gets(str);
		matubi = atoi2(str,-1);
	}
	while(OtoZero == -1){
		printf("oO(オー)を0に変換する場合は1を、しないなら0を入力してください\n>");
		gets(str);
		OtoZero = atoi2(str,-1);
	}
	if(0 == geturl(url)){
		printf("Error: ThreName NotFound\n");
		return 1;
	}
	s = get(url);
	if(s == NULL){
		printf("Error: DatFile NotFound\nURL:%s\n",url);
		return 1;
	}

	list = getidlist(s);
	if(list != NULL){
		sum = 0;
		max = 0;
		count = 0;
		zero = 0;
		str[0] = '\0';
		while(list->id[0] != '\0'){
			count++;
			temp = id2money(list);
			//printf("%s:%d\n",list->id,temp);
			sum += temp;
			if(temp >= max){
				max = temp;
				max_p = list;
			}
			if(temp == 0){
				//printf("%s\n",list->id);
				sprintf(&str[strlen(str)],">>%d ",list->num);
				zero++;
			}
			list++;
		}
	}
	sprintf(&str[strlen(str)-1],"\n");
	fileout("夢想封印.txt",str);
	//printf("%s",str);
	sprintf(str,"%d人が入れたようです。\nそのうち0円の人を除くと%d人が入れてくれたようです。\n最高金額の人 >>%d の人:\\%d\n合計:\\%d\n",count,count-zero,max_p->num,max,sum);
	fileout("結果.txt",str);
	//printf("%s",str);
	//printf("Money is %d\nmax:%s %d\n",sum,max_p,max);

	printf("処理を終了します。\n結果.txt に結果を記録しました。\n夢想封印.txt に0円/英字のみだった人を記録しました。\n終了するにはenterを押してください\n");
	gets(str);
	return 0;
}