3 * UCC (University [of WA] Computer Club) Electronic Accounting System
5 * itemdb.c - Dispense Item Databse
7 * This file is licenced under the 3-clause BSD Licence. See the file COPYING
20 extern tHandler gCoke_Handler;
21 extern tHandler gSnack_Handler;
22 extern tHandler gDoor_Handler;
25 void Init_Handlers(void);
26 void Load_Itemlist(void);
27 void Items_ReadFromFile(void);
28 char *trim(char *__str);
32 tItem *gaItems = NULL;
33 time_t gItems_LastUpdated;
34 tHandler gPseudo_Handler = {Name:"pseudo"};
35 tHandler *gaHandlers[] = {&gPseudo_Handler, &gCoke_Handler, &gSnack_Handler, &gDoor_Handler};
36 int giNumHandlers = sizeof(gaHandlers)/sizeof(gaHandlers[0]);
37 char *gsItemListFile = DEFAULT_ITEM_FILE;
41 regex_t gItemFile_Regex;
47 for( i = 0; i < giNumHandlers; i ++ )
49 if( gaHandlers[i]->Init )
50 gaHandlers[i]->Init(0, NULL); // TODO: Arguments
53 // Use inotify to watch the snack config file
58 giItem_INotifyFD = inotify_init();
59 inotify_add_watch(giItem_INotifyFD, gsItemListFile, IN_MODIFY);
62 signal(SIGIO, &ItemList_Changed);
64 // Fire SIGIO when data is ready on the FD
65 fcntl(giItem_INotifyFD, F_SETOWN, getpid());
66 oflags = fcntl(giItem_INotifyFD, F_GETFL);
67 fcntl(giItem_INotifyFD, F_SETFL, oflags | FASYNC);
73 void ItemList_Changed(int signum)
76 read(giItem_INotifyFD, buf, 512);
79 signum = 0; // Shut up GCC
84 * \brief Read the initiali item list
86 void Load_Itemlist(void)
89 rv = regcomp(&gItemFile_Regex, "^-?([a-zA-Z][a-zA-Z]*)\\s+([0-9]+)\\s+([0-9]+)\\s+(.*)", REG_EXTENDED);
92 size_t len = regerror(rv, &gItemFile_Regex, NULL, 0);
94 regerror(rv, &gItemFile_Regex, errorStr, len);
95 fprintf(stderr, "Rexex compilation failed - %s\n", errorStr);
101 // Re-read the item file periodically
102 // TODO: Be less lazy here and check the timestamp
103 AddPeriodicFunction( Items_ReadFromFile );
106 * \brief Read the item list from disk
108 void Items_ReadFromFile(void)
116 regmatch_t matches[5];
118 if( gItems_LastUpdated )
121 if( stat(gsItemListFile, &buf) ) {
122 fprintf(stderr, "Unable to stat() item file '%s'\n", gsItemListFile);
126 // Check if the update is needed
127 if( gItems_LastUpdated > buf.st_mtime )
132 fp = fopen(gsItemListFile, "r");
134 fprintf(stderr, "Unable to open item file '%s'\n", gsItemListFile);
135 perror("Unable to open item file");
138 while( fgets(buffer, BUFSIZ, fp) )
148 tmp = strchr(buffer, '#');
150 tmp = strchr(buffer, ';');
156 if(strlen(line) == 0) continue;
158 // Pass regex over line
159 if( RunRegex( &gItemFile_Regex, line, 5, matches, NULL) ) {
160 fprintf(stderr, "Syntax error on line %i of item file '%s'\n", lineNum, gsItemListFile);
165 type = line + matches[1].rm_so; line[ matches[1].rm_eo ] = '\0';
166 num = atoi( line + matches[2].rm_so );
167 price = atoi( line + matches[3].rm_so );
168 desc = line + matches[4].rm_so;
170 printf("Item '%s' - %i cents, %s:%i\n", desc, price, type, num);
173 for( i = 0; i < giNumHandlers; i ++ )
175 if( strcmp(type, gaHandlers[i]->Name) == 0 ) {
176 handler = gaHandlers[i];
182 fprintf(stderr, "Unknow item type '%s' on line %i (%s)\n", type, lineNum, desc);
186 for( i = 0; i < numItems; i ++ )
188 if( items[i].Handler != handler ) continue;
189 if( items[i].ID != num ) continue;
191 printf("Redefinition of %s:%i, updated\n", handler->Name, num);
192 items[i].Price = price;
194 items[i].Name = strdup(desc);
197 if( i < numItems ) continue;
199 items = realloc( items, (numItems + 1)*sizeof(items[0]) );
200 items[numItems].Handler = handler;
201 items[numItems].ID = num;
202 items[numItems].Price = price;
203 items[numItems].Name = strdup(desc);
204 items[numItems].bHidden = (line[0] == '-');
217 giNumItems = numItems;
220 gItems_LastUpdated = time(NULL);
223 char *trim(char *__str)
228 while( isspace(*__str) )
233 while( i-- && isspace(__str[i]) ) {