리눅스
1차 과제 완료
정지홍
2023. 3. 29. 00:55
//2020y ~ 2024y
//-n은 이름, -y는 연도 , -a는 연봉
/*show -a*/ //전 직원 평균 연봉
/*show -n hong*/ //이름만 입력시 매년 정보 출력
/*show -a -y 2021*/ //해당연도 평균 연봉
/*show -n hong -y 2021*/ //이름 및 연도만 입력시 해당연도 연봉
//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);//argc가 2 혹은 4인 경우에 사용하는 함수입니다.
void argc_n_name(int fd,char *optarg,int y);//argc가 3 혹은 5인 경우에 사용하는 함수입니다.
int main(int argc , char *argv[]){
int fd1,fd2,fd3,fd4,fd5;//파일 기술자 각각 txt1부터 txt5까지.
int n;
//차례대로 텍스트파일을 읽기 전용으로 열어줍니다.
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);
}
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개인 경우입니다.
while( (n=getopt(argc,argv,"n:"))!=-1){//argv에 -n존재시 반복하며 :을 추가해서 이중 옵션으로 이름을 입력받습니다.
switch(n){
case 'n'://(./show -n Hong(옵션인자)인 경우)
//optarg는 이중 옵션으로 받은 경우 뒤쪽에 있는 옵션이 저장되며 여기에서는 이름이 저장되어있습니다.
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;
}
}
}
if(argc==4){//입력받은 인자가 4개인 경우(>show -a -y 2021)입니다.
int isA=0;//-a가 입력되었는지 확인하는 변수입니다.
while( (n=getopt(argc,argv,"y:a"))!=-1){//-y는 이중인자로 입력을 받으며 a는 인자를 받지 않습니다.
switch(n){
case 'a'://-a -y year을 위해서 우선 a가 입력되었는지 확인합니다. 이 케이스문 빠지면 isA=1로 변경합니다.
isA=1;
break;
case 'y':
if(isA==0){//처음 입력받은 인자가 a가 아닌경우 break를 걸어줍니다.
break;
}
//optarg는 옵션의 인자값을 나타내며 getopt()호출마다 다시 설정됩니다. 인자가 없으면 널을 나타내줍니다.
//이 경우에는 -a옵션의 인자는 널이며 -y의 인자는 연도를 전달받습니다.
char *year=optarg;//전달받은 인자를 저장하는 변수입니다.
if(strcmp(year,"2020")==0){//strcmp로 해당되는 연도를 찾습니다.
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;
}
}
}
if(argc==5){//전달 받은 인자가 5개인 경우입니다.(/show -n Hong -y 2021)
char *name;//입력받은 이름을 저장할 변수입니다.
char *year;//연도를 저장할 변수입니다.
while( (n=getopt(argc,argv,"n:y:"))!=-1){//-n과 -y는 옵션인자를 같이 입력받습니다
switch(n){
case 'n':
name=optarg;//입력받은 이름을 저장합니다.
case 'y':
year=optarg;//변수에 연도를 저장합니다.
if (strcmp(year,"2020")==0){
argc_n_name(fd1,name,2020);
}
else if (strcmp(year,"2021")==0){
argc_n_name(fd2,name,2021);
}
else if (strcmp(year,"2022")==0){
argc_n_name(fd3,name,2022);
}
else if (strcmp(year,"2023")==0){
argc_n_name(fd4,name,2023);
}
else if (strcmp(year,"2024")==0){
argc_n_name(fd5,name,2024);
}
}
}
}
//파일을 닫아줍니다.
close(fd1);
close(fd2);
close(fd3);
close(fd4);
close(fd5);
return 0;
}
void argc_a_y_year(int fd,int y){//argc가 2 혹은 4인 경우에 사용하는 함수입니다.
char buf[1];//버퍼를 선언합니다.
int n;//read함수에서 사용할 변수입니다. 리드함수는 실행마다 읽어온 크기만큼 오프셋이 이동합니다.
int cnt=1;//텍스트 파일에 처음 숫자는 입사한 연도이니 이것을 구별하기 위한 변수입니다.(총 카운트값이 1~4이면 입사연도를 입력받고 있음을 뜻합니다.)
int rst=0;//각각 자릿수마다 더 해질 변수입니다.
int sum=0;//사원들의 연봉 합을 저장하는 변수입니다.
int bunmo=0;//사원수를 카운트하는 변수입니다.
float avg;//연봉 평균을 저장할 변수입니다.
while((n=read(fd,buf,1))>0){//파일기술자가 가르키는 파일을 1바이트씩 읽습니다. 그리고 buf에 잠시 저장합니다. 한글은 2바이트이니 읽지 않습니다.
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){//argc가 3 혹은 5인 경우에 사용하는 함수입니다.
//함수는 파일기술자와 이름 그리고 연도를 차례로 입력받습니다.
int n;//read함수에서 사용할 변수입니다. 리드함수는 실행마다 읽어온 크기만큼 오프셋이 이동합니다.
char buf[512];//버퍼를 선언합니다.
memset(buf,'\0',sizeof(buf));//memset함수를 이용하여 buf가 가르키는 메모리를 초기화합니다.
while((n=read(fd,buf,1))>0){//파일 기술자가 가르키는 연도의 사원 파일에서 1바이트씩 읽습니다. 그리고 buf에 저장합니다.
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문에 빠지지 않으며 아래의 if문에 들어가도 optarg로 전달받은 이름과 비교해도 조건에 만족을 못합니다.
while(*buf>=97 && *buf<=122){//이번에 읽은 문자가 소문자인 경우에만 반복문이 실행됩니다.
strncat(rtn,buf,strlen(buf));//저장된 문자열에 계속해서 문자를 더해줍니다.
n=read(fd,buf,1);//다음 문자를 읽어줍니다.
}
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,10);//다시 read함수로 읽어오고 다음 출력을 위해 오프셋을 이동시켜줍니다.
printf("%s. 연봉: ",buf);
buf[5]='\0';//다음을 위해서 버퍼 6번째 자리에 널을 넣어줍니다.
n=read(fd,buf,5);//다시 read함수로 읽어오고 다음 출력을 위해 오프셋을 이동시켜줍니다.
printf("%s. ",buf);
buf[2]='\0';//다음을 위해서 버퍼 3번째 자리에 널을 넣습니다.
n=read(fd,buf,2);//다시 read함수로 읽어오고 다음 출력을 위해 오프셋을 이동시켜줍니다.
printf("근무 평점: %s\n",buf);
break;
}
}
}
}