typedef struct sItem {
char *Type;
int ID;
+ int Status; // 0: Availiable, 1: Sold out, -1: Error
char *Desc;
int Price;
} tItem;
void ShowUsage(void);
// --- GUI ---
int ShowNCursesUI(void);
- int ShowItemAt(int Row, int Col, int Width, int Index);
+ int ShowItemAt(int Row, int Col, int Width, int Index, int bHilighted);
void PrintAlign(int Row, int Col, int Width, const char *Left, char Pad1, const char *Mid, char Pad2, const char *Right, ...);
// --- Coke Server Communication ---
int OpenConnection(const char *Host, int Port);
// -- Create regular expressions
// > Code Type Count ...
CompileRegex(&gArrayRegex, "^([0-9]{3})\\s+([A-Za-z]+)\\s+([0-9]+)", REG_EXTENDED); //
- // > Code Type Ident Price Desc
- CompileRegex(&gItemRegex, "^([0-9]{3})\\s+([A-Za-z]+)\\s+([A-Za-z]+):([0-9]+)\\s+([0-9]+)\\s+(.+)$", REG_EXTENDED);
+ // > Code Type Ident Status Price Desc
+ CompileRegex(&gItemRegex, "^([0-9]{3})\\s+([A-Za-z]+)\\s+([A-Za-z]+):([0-9]+)\\s+(avail|sold|error)\\s+([0-9]+)\\s+(.+)$", REG_EXTENDED);
// > Code 'SALT' salt
CompileRegex(&gSaltRegex, "^([0-9]{3})\\s+([A-Za-z]+)\\s+(.+)$", REG_EXTENDED);
// > Code 'User' Username Balance Flags
int itemCount;
int maxItemIndex;
int itemBase = 0;
- int currentItem = 0;
+ int currentItem;
int ret = -2; // -2: Used for marking "no return yet"
char balance_str[5+1+2+1]; // If $9999.99 is too little, something's wrong
raw(); noecho();
// Get max index
- maxItemIndex = ShowItemAt(0, 0, 0, -1);
+ maxItemIndex = ShowItemAt(0, 0, 0, -1, 0);
// Get item count per screen
// - 6: randomly chosen (Need at least 3)
itemCount = LINES - 6;
if( itemCount > maxItemIndex )
itemCount = maxItemIndex;
// Get first index
- while( ShowItemAt(0, 0, 0, currentItem) == -1 )
+ currentItem = 0;
+ while( ShowItemAt(0, 0, 0, currentItem, 0) == -1 )
currentItem ++;
int pos = 0;
move( yBase + 1 + i, xBase );
+ printw("| ");
- if( currentItem == itemBase + i ) {
- printw("| ->");
- }
- else {
- printw("| ");
- }
- pos += 4;
+ pos += 2;
// Check for the '...' row
// - Oh god, magic numbers!
if( (i == 0 && itemBase > 0)
|| (i == itemCount - 1 && itemBase < maxItemIndex - itemCount) )
{
- printw(" ..."); pos += 6;
+ printw(" ..."); pos += 8;
times = (width - pos) - 1;
- //times = width-1 - 8 - 3;
while(times--) addch(' ');
}
// Show an item
else {
- ShowItemAt( yBase + 1 + i, xBase + pos, (width - pos) - 3, itemBase + i);
+ ShowItemAt(
+ yBase + 1 + i, xBase + pos, // Position
+ (width - pos) - 3, // Width
+ itemBase + i, // Index
+ !!(currentItem == itemBase + i) // Hilighted
+ );
printw(" ");
}
case 'B':
currentItem ++;
// Skip over spacers
- while( ShowItemAt(0, 0, 0, currentItem) == -1 )
+ while( ShowItemAt(0, 0, 0, currentItem, 0) == -1 )
currentItem ++;
if( currentItem >= maxItemIndex ) {
currentItem = 0;
// Skip over spacers
- while( ShowItemAt(0, 0, 0, currentItem) == -1 )
+ while( ShowItemAt(0, 0, 0, currentItem, 0) == -1 )
currentItem ++;
}
break;
case 'A':
currentItem --;
// Skip over spacers
- while( ShowItemAt(0, 0, 0, currentItem) == -1 )
+ while( ShowItemAt(0, 0, 0, currentItem, 0) == -1 )
currentItem --;
if( currentItem < 0 ) {
currentItem = maxItemIndex - 1;
// Skip over spacers
- while( ShowItemAt(0, 0, 0, currentItem) == -1 )
+ while( ShowItemAt(0, 0, 0, currentItem, 0) == -1 )
currentItem --;
}
break;
switch(ch)
{
case '\n':
- ret = ShowItemAt(0, 0, 0, currentItem);
+ ret = ShowItemAt(0, 0, 0, currentItem, 0);
break;
case 'q':
ret = -1; // -1: Return with no dispense
* \return Dispense index of item
* \note Part of the NCurses UI
*/
-int ShowItemAt(int Row, int Col, int Width, int Index)
+int ShowItemAt(int Row, int Col, int Width, int Index, int bHilighted)
{
int _x, _y, times;
char *name = NULL;
int price = 0;
+ int status = -1;
switch(giUIMode)
{
{
name = gaItems[Index].Desc;
price = gaItems[Index].Price;
+ status = gaItems[Index].Status;
break;
}
Index -= 7;
Index += 7;
name = gaItems[Index].Desc;
price = gaItems[Index].Price;
+ status = gaItems[Index].Status;
break;
default:
return -1;
if( Index >= 0 )
{
- printw("%02i %s", Index, name);
+ // Show hilight and status
+ switch( status )
+ {
+ case 0:
+ if( bHilighted )
+ printw("-> ");
+ else
+ printw(" ");
+ break;
+ case 1:
+ printw("SLD");
+ break;
+
+ default:
+ case -1:
+ printw("ERR");
+ break;
+ }
+
+ printw(" %s", name);
getyx(stdscr, _y, _x);
// Assumes max 4 digit prices
- times = Width - 4 - (_x - Col); // TODO: Better handling for large prices
+ times = Width - 5 - (_x - Col); // TODO: Better handling for large prices
while(times--) addch(' ');
- printw("%4i", price);
+
+ printw(" %4i", price);
}
else
{
printw("-- %s", name);
getyx(stdscr, _y, _x);
- times = Width - 4 - (_x - Col); // TODO: Better handling for large prices
+ times = Width - 4 - (_x - Col);
while(times--) addch(' ');
- printw(" --", price);
+ printw(" ");
}
}
+ // If the item isn't availiable for sale, return -1 (so it's skipped)
+ if( status )
+ Index = -1;
+
return Index;
}
return 0;
}
+/**
+ * \brief Read an item info response from the server
+ * \param Dest Destination for the read item (strings will be on the heap)
+ */
+int ReadItemInfo(int Socket, tItem *Dest)
+{
+ char *buf;
+ int responseCode;
+
+ regmatch_t matches[8];
+ char *statusStr;
+
+ // Get item info
+ buf = ReadLine(Socket);
+ responseCode = atoi(buf);
+
+ switch(responseCode)
+ {
+ case 202: break;
+
+ case 406:
+ printf("Bad item name\n");
+ free(buf);
+ return 1;
+
+ default:
+ fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n%s", responseCode, buf);
+ exit(-1);
+ }
+
+ RunRegex(&gItemRegex, buf, 8, matches, "Malformed server response");
+
+ buf[ matches[3].rm_eo ] = '\0';
+ buf[ matches[5].rm_eo ] = '\0';
+ buf[ matches[7].rm_eo ] = '\0';
+
+ statusStr = &buf[ matches[5].rm_so ];
+
+ Dest->ID = atoi( buf + matches[4].rm_so );
+
+ if( strcmp(statusStr, "avail") == 0 )
+ Dest->Status = 0;
+ else if( strcmp(statusStr, "sold") == 0 )
+ Dest->Status = 1;
+ else if( strcmp(statusStr, "error") == 0 )
+ Dest->Status = -1;
+ else {
+ fprintf(stderr, "Unknown response from dispense server (status '%s')\n",
+ statusStr);
+ return 1;
+ }
+ Dest->Price = atoi( buf + matches[6].rm_so );
+
+ // Hack a little to reduce heap fragmentation
+ {
+ char tmpType[strlen(buf + matches[3].rm_so) + 1];
+ char tmpDesc[strlen(buf + matches[7].rm_so) + 1];
+ strcpy(tmpType, buf + matches[3].rm_so);
+ strcpy(tmpDesc, buf + matches[7].rm_so);
+ free(buf);
+ Dest->Type = strdup( tmpType );
+ Dest->Desc = strdup( tmpDesc );
+ }
+
+ return 0;
+}
/**
* \brief Fill the item information structure
// Fetch item information
for( i = 0; i < giNumItems; i ++ )
{
- regmatch_t matches[7];
-
- // Get item info
- buf = ReadLine(Socket);
- responseCode = atoi(buf);
-
- if( responseCode != 202 ) {
- fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n", responseCode);
- exit(-1);
- }
-
- RunRegex(&gItemRegex, buf, 7, matches, "Malformed server response");
-
- buf[ matches[3].rm_eo ] = '\0';
-
- gaItems[i].Type = strdup( buf + matches[3].rm_so );
- gaItems[i].ID = atoi( buf + matches[4].rm_so );
- gaItems[i].Price = atoi( buf + matches[5].rm_so );
- gaItems[i].Desc = strdup( buf + matches[6].rm_so );
-
- free(buf);
+ ReadItemInfo( Socket, &gaItems[i] );
}
// Read end of list
*/
int Dispense_ItemInfo(int Socket, const char *Type, int ID)
{
- int responseCode;
- char *buf;
- regmatch_t matches[7];
- char *type, *desc;
- int id, price;
+ tItem item;
- // Dispense!
+ // Query
sendf(Socket, "ITEM_INFO %s:%i\n", Type, ID);
- buf = ReadLine(Socket);
- responseCode = atoi(buf);
- switch( responseCode )
+ if( ReadItemInfo(Socket, &item) )
{
- case 202:
- break;
-
- case 406:
- printf("Bad item name\n");
- free(buf);
- return 1;
-
- default:
- printf("Unknown response code %i ('%s')\n", responseCode, buf);
- free(buf);
return -1;
}
-
- RunRegex(&gItemRegex, buf, 7, matches, "Malformed server response");
-
- buf[ matches[3].rm_eo ] = '\0';
-
- type = buf + matches[3].rm_so; buf[matches[3].rm_eo] = '\0';
- id = atoi( buf + matches[4].rm_so );
- price = atoi( buf + matches[5].rm_so );
- desc = buf + matches[6].rm_so; buf[matches[6].rm_eo] = '\0';
+ printf("%8s:%-2i %2i.%02i %s\n",
+ item.Type, item.ID,
+ item.Price/100, item.Price%100,
+ item.Desc);
- printf("%8s:%-2i %2i.%02i %s\n", type, id, price/100, price%100, desc);
-
- free(buf);
+ free(item.Type);
+ free(item.Desc);
return 0;
}