본문 바로가기

Information Technology/C

[C언어] MP3 관리 프로그램(4)

1. add_artist

Artist* create_artist_instance(char* name) // Artist 객체를 생성하는 함수
{
	Artist* ptr_artist = (Artist*)malloc(sizeof(Artist)); 
	ptr_artist->name = name;
	ptr_artist->head = NULL;
	ptr_artist->tail = NULL;
	ptr_artist->next = NULL;
	return ptr_artist;
}

Artist* add_artist(char* name)
{
	// Artist 객체를 만드는 일을 함수에게 맡김
	Artist* ptr_artist = create_artist_instance(name);
	Artist* p = artist_directory[(unsigned char)name[0]]; // 새롭게 만들 연결리스트의 첫 번째(배열의 이름)
	Artist* q = NULL;	// 연결 리스트에서 p를 따라가며 위치를 기억하는 용도

	while (p != NULL && strcmp(p->name, name) < 0)	// ordered list에서 p보다 작은 값이 나타날 때 까지

	{
		q = p;
		p = p->next;
	}

	if (p == NULL && q == NULL) // 리스트가 비어있을 때. 즉 p가 유일한 노드가 됨
	{
		artist_directory[(unsigned char)name[0]] == ptr_artist;
	}
	else if (q == NULL)	// p가 맨 앞에 위치할 때
	{
		ptr_artist->next = artist_directory[(unsigned char)name[0]];
		artist_directory[(unsigned char)name[0]] = ptr_artist;
	}
	else	// 리스트의 중간에 추가될 때
	{
		ptr_artist->next = p;
		q->next = ptr_artist;
	}

	return ptr_artist;
}

2. add_song

void insert_node(Artist* ptr_artist, SNode* ptr_snode)
{
	SNode* p = ptr_artist->head;
    
	// head에 저장된 값보다 ptr_snode에 저장된 제목이 클 때까지 while문 반복
	while (p != NULL && strcmp(p->song->title, ptr_snode->song->title)<0) 
		p = p->next;
	// p가 ptr_snode가 들어갈 자리보다 한 자리 뒤에 있기 때문에 p의 앞 위치에 새로운 snode를 대입
	// 1. 연결리스트가 비어있을 때 2. 맨 앞에 대입할 때 3. 맨 뒤에 대입할 때 4. 노래 사이에 대입
	if (ptr_artist->head == NULL) { // 1번 케이스
		ptr_artist->head = ptr_snode;
		ptr_artist->tail = ptr_snode;	// 리스트의 유일한 곡이기 때문에 이중연결리스트의 head와 tail이 모두 ptr_snode
	}
	else if (p == ptr_artist->head) { // 2번 케이스.
		ptr_snode->next = ptr_artist->head;
		ptr_artist->head->prev = ptr_snode;
		ptr_artist->head = ptr_snode; // 새로운 곡이 곡 리스트의 첫 번째 곡 자리에 위치함
	}
	else if(p==NULL){ // 3번 케이스. 
		ptr_snode->prev = ptr_artist->tail;
		ptr_artist->tail->next = ptr_snode;
		ptr_artist->tail = ptr_snode;
	}
	else {	// 4번 케이스. p 앞에 노래를 추가
		ptr_snode->next = p;
		ptr_snode->prev = p->prev;
		p->prev->next = ptr_snode;
		p->prev = ptr_snode;
	}
}

void add_song(char* artist, char* title, char* path)
{
	// 가수가 이미 존재하는 경우
	// 존재하지 않는다면 NULL return
	Artist* ptr_artist = find_artist(artist);	// 가수를 찾아서 Artist 포인터를 return
	if (ptr_artist == NULL)	// 만약 가수가 플레이리스트에 존재하지 않는다면
	{
		ptr_artist = add_artist(artist); // artist라는 이름을 가진 Artist 객체를 하나 추가하여 그 주소를 리턴
	}

	Song* ptr_song = create_song_instance(ptr_artist, title, path);
	SNode* ptr_snode = (SNode*)malloc(sizeof(SNode));
	ptr_snode->song = ptr_song;	// SNode들끼리 이중연결리스트로 연결되는 구조.
	ptr_snode->next = NULL; // 의도치 않은 실수를 방지하기 위해 구조체의 포인터 값은 null로 설정해주는 것도 좋음

	// insert node
	insert_node(ptr_artist, ptr_snode);
}

3. status를 통해 상태 확인

void status()
{
	for (int i = 0; i < NUM_CHARS; i++)
	{
			Artist* p = artist_directory[i];	// 
			while (p!=NULL)
			{
				print_artist(p);
				p = p->next;
			}
	}
}

void print_artist(Artist* p)
{
	printf("name: %s\n", p->name);
	SNode* ptr_snode = p->head;
	while (ptr_snode != NULL)
	{
		print_song(ptr_snode->song);
		ptr_snode = ptr_snode->next;
	}
}

void print_song(Song* ptr_song)
{
	printf("%d: %s, %s\n", ptr_song->index, ptr_song->title, ptr_song->path);
}

4. load file

1) main.cpp

int main()
{
	initialize();	// Artist 배열을 초기화
	handle_load();	// process_command() 이전에 미리 파일을 로드할 것인지 물어봄
	process_command();
}

2. library.cpp

void load(FILE* fp)
{
	char buffer[BUFFER_LENGTH];
	char* name, * title, * path;

	while (1)
	{
		if (read_line(fp, buffer, BUFFER_LENGTH) <= 0) // fp에 저장한 입력 스트림으로부터 데이터를 읽음
			break;
		name = strtok(buffer, "#");	// 공백문자 전까지 tokenize하여 저장
		if (strcmp(name, " ") == 0) // 이름이 존재하지 않는다면
			name = NULL;
		else
			name = strdup(name); // 이름을 복제하여 저장

		title = strtok(NULL, "#");	// 공백문자 전까지 tokenize하여 저장
		if (strcmp(title, " ") == 0) // 이름이 존재하지 않는다면
			title = NULL;
		else
			title = strdup(title); // 이름을 복제하여 저장

		path = strtok(NULL, "#");	// 공백문자 전까지 tokenize하여 저장
		if (strcmp(path, " ") == 0) // 이름이 존재하지 않는다면
			path = NULL;
		else
			path = strdup(path); // 이름을 복제하여 저장
		printf("%s %s %s\n", name, title, path);
	}
}