1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERPUTT is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include "common.h"
20 #include "config.h"
21 #include "course.h"
22 #include "hole.h"
23 #include "fs.h"
24 
25 /*---------------------------------------------------------------------------*/
26 
27 struct course
28 {
29     char holes[MAXSTR];
30 
31     char shot[MAXSTR];
32     char desc[MAXSTR];
33 };
34 
35 static int course_state = 0;
36 
37 static int course;
38 static int count;
39 
40 static struct course course_v[MAXCRS];
41 
42 /*---------------------------------------------------------------------------*/
43 
course_load(struct course * crs,const char * filename)44 static int course_load(struct course *crs, const char *filename)
45 {
46     fs_file fin;
47     int rc = 0;
48 
49     memset(crs, 0, sizeof (*crs));
50 
51     strncpy(crs->holes, filename, MAXSTR - 1);
52 
53     if ((fin = fs_open(filename, "r")))
54     {
55         if (fs_gets(crs->shot, sizeof (crs->shot), fin) &&
56             fs_gets(crs->desc, sizeof (crs->desc), fin))
57         {
58             strip_newline(crs->shot);
59             strip_newline(crs->desc);
60 
61             rc = 1;
62         }
63 
64         fs_close(fin);
65     }
66 
67     return rc;
68 }
69 
cmp_dir_items(const void * A,const void * B)70 static int cmp_dir_items(const void *A, const void *B)
71 {
72     const struct dir_item *a = A, *b = B;
73     return strcmp(a->path, b->path);
74 }
75 
course_is_loaded(const char * path)76 static int course_is_loaded(const char *path)
77 {
78     int i;
79 
80     for (i = 0; i < count; i++)
81         if (strcmp(course_v[i].holes, path) == 0)
82             return 1;
83 
84     return 0;
85 }
86 
is_unseen_course(struct dir_item * item)87 static int is_unseen_course(struct dir_item *item)
88 {
89     return (str_starts_with(base_name(item->path), "holes-") &&
90             str_ends_with(item->path, ".txt") &&
91             !course_is_loaded(item->path));
92 }
93 
course_init()94 void course_init()
95 {
96     fs_file fin;
97     char *line;
98 
99     Array items;
100     int i;
101 
102     if (course_state)
103         course_free();
104 
105     count = 0;
106 
107     if ((fin = fs_open(COURSE_FILE, "r")))
108     {
109         while (count < MAXCRS && read_line(&line, fin))
110         {
111             if (course_load(&course_v[count], line))
112                 count++;
113 
114             free(line);
115         }
116 
117         fs_close(fin);
118 
119         course_state = 1;
120     }
121 
122     if ((items = fs_dir_scan("", is_unseen_course)))
123     {
124         array_sort(items, cmp_dir_items);
125 
126         for (i = 0; i < array_len(items) && count < MAXCRS; i++)
127             if (course_load(&course_v[count], DIR_ITEM_GET(items, i)->path))
128                 count++;
129 
130         fs_dir_free(items);
131 
132         course_state = 1;
133     }
134 }
135 
course_exists(int i)136 int course_exists(int i)
137 {
138     return (0 <= i && i < count);
139 }
140 
course_count(void)141 int course_count(void)
142 {
143     return count;
144 }
145 
course_goto(int i)146 void course_goto(int i)
147 {
148     hole_init(course_v[i].holes);
149     course = i;
150 }
151 
course_curr(void)152 int course_curr(void)
153 {
154     return course;
155 }
156 
course_free(void)157 void course_free(void)
158 {
159     hole_free();
160     course_state = 0;
161 }
162 
course_rand(void)163 void course_rand(void)
164 {
165     course_goto(rand() % count);
166     hole_goto(rand() % curr_count(), 4);
167 }
168 
169 /*---------------------------------------------------------------------------*/
170 
course_desc(int i)171 const char *course_desc(int i)
172 {
173     return course_exists(i) ? course_v[i].desc : "";
174 }
175 
course_shot(int i)176 const char *course_shot(int i)
177 {
178     return course_exists(i) ? course_v[i].shot : course_v[0].shot;
179 }
180 
181 /*---------------------------------------------------------------------------*/
182