리눅스

일단 다 함수로 구현. 이제 argc==5인 케이스만

정지홍 2023. 3. 27. 12:12
//기본 경우 수
//-n은 이름, -y는 연도 , -a는 연봉
/*show -n hong*/ //이름만 입력시 매년 정보 출력
/*show -n hong -y 2021*/ //이름 및 연도만 입력시 해당연도 연봉
/*show -a*/	//전 직원 평균 연봉
/*show -a -y 2021*/ //해당연도 평균 연봉
//2020y ~ 2024y
//나중에 추가해볼것
//-b 부서 , -g 근문 평점, -e입사년도
//argc가 2인 경우:->./show -a 
//argc가 3인 경우:->./show -n Hong  
//argc가 4인 경우:->./show -a -y 2021 
//argc가 5인 경우:->./show -n Hong -y 2021
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
void argc_a_y_year(int fd,int y);
void argc_n_name(int fd,char *optarg,int y);
int main(int argc , char *argv[]){

	int fd1,fd2,fd3,fd4,fd5;//파일 기술자 각각 txt1부터 txt5까지.
	int n;//스업예제로 테스트 나중에 지우기 
	char buf[512];
	
	//차례대로 텍스트파일을 읽기 전용으로 열어줍니다.
	fd1=open("data1.txt",O_RDONLY);
	if (fd1==-1){
		perror("data1.txt");
		exit(1);
	}
	fd2=open("data2.txt",O_RDONLY);
	if (fd2==-1){
		perror("data2.txt");
		exit(1);
	}
	fd3=open("data3.txt",O_RDONLY);
	if (fd3==-1){
		perror("data3.txt");
		exit(1);
	}
	fd4=open("data4.txt",O_RDONLY);
	if (fd4==-1){
		perror("data4.txt");
		exit(1);
	}
	fd5=open("data5.txt",O_RDONLY);
	if (fd5==-1){
		perror("data1.txt");
		exit(1);
	}
	extern char *oparg;
	extern int optind;
	if(argc==2){//전달 받은 인자가 2개인 경우
			while( (n=getopt(argc,argv,"a"))!=-1){//argv에 -a존재시 반복하며 더이상 옵션이 없으면 -1을 리턴해서 반복문 탈출합니다.
				switch(n){
					case 'a'://매년 모든 직원의 연봉을 출력합니다.(./show -a)
						argc_a_y_year(fd1,2020);
						argc_a_y_year(fd2,2021);
						argc_a_y_year(fd3,2022);
						argc_a_y_year(fd4,2023);
						argc_a_y_year(fd5,2024);
					}
				}
	}

	if(argc==3){//전달받은 인자가 3개인 경우입니다.
			memset(buf,'\0',sizeof(buf));//memset함수를 이용하여 buf가 가르키는 메모리를 초기화합니다.
			while( (n=getopt(argc,argv,"n:y:a:"))!=-1){
				switch(n){
					case 'n'://(./show -n 옵션인자인 경우)
						argc_n_name(fd1,optarg,2020);
						argc_n_name(fd2,optarg,2021);
						argc_n_name(fd3,optarg,2022);
						argc_n_name(fd4,optarg,2023);
						argc_n_name(fd5,optarg,2024);
						break;
					case 'y':
						printf("Option : y , Argment=%s\n",optarg);
						break;
					case 'a':
						printf("Option : a , Argment=%s\n",optarg);
						break;
					}

				}
	}

	if(argc==4){//입력받은 인자가 4개인 경우(>show -a -y 2021)
		int isA=0;
			while( (n=getopt(argc,argv,"n:y:a"))!=-1){
				switch(n){
					case 'a':
						isA=1;
						break;
					case 'y':
						if(isA==0){
							//printf("check");
							break;
						}
						char *year=optarg;//optarg는 옵션의 인자값을 나타내며 getopt()호출마다 다시 설정됩니다. 인자가 없으면 널을 나타내줍니다.
						
						if(strcmp(year,"2020")==0){
							argc_a_y_year(fd1,2020);
						}
						else if(strcmp(year,"2021")==0){
							argc_a_y_year(fd2,2021);
						}
						else if(strcmp(year,"2022")==0){
							argc_a_y_year(fd3,2022);
						}
						else if(strcmp(year,"2023")==0){
							argc_a_y_year(fd4,2023);
						}
						else if(strcmp(year,"2024")==0){
							argc_a_y_year(fd5,2024);
						}
						break;
					case 'n':

						break;
					}

				}
	}

	return 0;
	



	//파일을 닫아줍니다.
	close(fd1);
	close(fd2);
	close(fd3);
	close(fd4);
	close(fd5);
	return 0;
}

void argc_a_y_year(int fd,int y){
	char buf[1];
	int n;//read함수에서 사용할 변수입니다. 리드함수는 실행마다 읽어온 크기만큼 오프셋이 이동합니다.
	int cnt=1;//텍스트 파일에 처음 숫자는 입사한 연도이니 이것을 구별하기 위한 변수입니다.
	int rst=0;//각각 자릿수마다 더 해질 변수입니다.
	int sum=0;//사원들의 연봉 합을 저장하는 변수입니다.
	int bunmo=0;//사원수를 카운트하는 변수입니다.
	float avg;//연봉 평균을 저장할 변수입니다.
						
	while((n=read(fd,buf,1))>0){
		if(*buf<48 || *buf>57){//버퍼에 숫자가 저장 안된 경우입니다.
			if(rst>=1000){//연봉이 네자리 이상인 경우에 실행합니다.(한 사원의 연봉이 다 구해진 경우.)
				sum+=rst;//사원의 연봉을 총합에 더해줍니다.
				rst=0;//그리고 다음 사원을 검색하기 위해 rst=0을 해줍니다..
				bunmo+=1;//사원수를 1명 더해줍니다.
				cnt=1;//다음 검색을 위해 카운트=1을 해줍니다.
			}
		}
		if(*buf>=48 && *buf<=57){//버퍼에 숫자가 저장된 경우입니다.
			int save=*buf;//버퍼에 저장된 수를 save변수에 저장합니다.
			save-=48;//아스키코드에서 십진수로 바꿔야하니 48을 빼줍니다.
				if(cnt>=5 && cnt<=9){//앞의 cnt가 1~4인경우는 입사년도이며 5~8or9는 연봉을 나타내는 숫자입니다.
					if(rst==0){//cnt=5인 경우이며 천의 자리 숫자 혹은 만의 자리 숫자입니다.
						rst=save;//rst에 저장해줍니다.
						cnt+=1;//다음 자리숫를 위해 cnt+=1일 합니다.
					}
					else{//cnt=6,7,8,9인 경우입니다. 연봉이 만의 자리 숫까지 가는 경우만 cnt=9까지 도달합니다.
						rst*=10;//기존 숫자에 자릿수를 앞으로 늘립니다.
						rst+=save;//뒤에 숫자를 더해줍니다.
						cnt+=1;//다음 연산을 위해서 1을 더해줍니다.
					}
				}
				else{//입사년도에 해당되는 케이스입니다.
					cnt+=1;//입사년도,연봉 구별하는 변수에 1을 더해줍니다.
				}
			}
	}
	avg=sum/bunmo;//평균 연봉을 구합니다.
	printf("%d년 직원의 평균 연봉은 %.2f입니다.\n",y,avg);

}

void argc_n_name(int fd,char *optarg,int y){
	int n;
	char buf[512];
	memset(buf,'\0',sizeof(buf));//memset함수를 이용하여 buf가 가르키는 메모리를 초기화합니다. (함수 다시 쓰는데 버퍼에 내용이 남아있나???)
	while((n=read(fd,buf,1))>0){//2020년도 사원 파일, 임시저장 버퍼,1바이트씩 읽습니다.
						
		char *name=optarg;//optarg는 옵션의 인자값을 나타내며 getopt()호출마다 다시 설정됩니다. 인자가 없으면 널을 나타내줍니다.
		char rtn[10]="";
		if(*buf>=65 && *buf<=90){//-n과 이름을 입력받으며 성의 첫글자는 대문자이니 아스키코드로 구분합니다.
	//단, 근무 평점도 대문자입니다. 그래서 아래 반복문으로 구별할 예정입니다.
	//만약 지금이 근무 평점이면 다음에 읽는 문자도 대문자 알파벳입니다.
			strncat(rtn,buf,strlen(buf));//빈 문자열에 buf에 저장된 대문자를 더합니다.
			n=read(fd,buf,1);//그리고 다음 문자를 읽어줍니다.
						
			while(*buf>=97 && *buf<=122){//이번에 읽은 문자가 소문자인 경우에만 반복문이 실행됩니다.
				strncat(rtn,buf,strlen(buf));//저장된 문자열에 계속해서 문자를 더해줍니다.
				n=read(fd,buf,1);//다음 문자를 읽어줍니다.						
			}
			//printf("%s \n",buf);
			if ((strcmp(rtn,name)==0)){//현재 rtn에 저장된 이름과 name이 일치한 경우 사원 정보를 출력을 시작합니다. 
				printf("%d년->이름:%s , 입사연도:",y,name);
				n=read(fd,buf,5);
				printf("%s",buf);
				printf(", 근무부서: ");
				n=read(fd,buf,9);
				printf("%s. 연봉: ",buf);
				buf[5]='\0';
				n=read(fd,buf,5);
				printf("%s. ",buf);
				buf[2]='\0';
				n=read(fd,buf,2);
				printf("근무 평점: %s\n",buf);
				break;
			}
								
		}
	}
	//printf("함수종료\n");
}