1 #include "config.h"
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <getopt.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <sys/mman.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include "types.h"
12 
13 #define roundup(x,y) (((x) + (y) - 1) & ~((y) - 1))
14 
15 int usecolor = 0;
16 int savesamples = 0;
17 FILE *savepatterns = 0;
18 
19 char *FONT_RESET = "";
20 char *FONT_BRIGHT_BLACK = "";
21 char *FONT_BRIGHT_RED = "";
22 char *FONT_BRIGHT_GREEN = "";
23 char *FONT_BRIGHT_YELLOW = "";
24 char *FONT_BRIGHT_BLUE = "";
25 char *FONT_BRIGHT_PURPLE = "";
26 char *FONT_BRIGHT_CYAN = "";
27 
28 struct
29 {
30 	uint32_t offset;
31 	uint16_t length;
32 } Instruments[31];
33 
34 #if 0
35 typedef struct __attribute__((packed))
36 {
37 	char name[20];
38 	char tracker[8];
39 	uint8_t sig,type;
40 	uint8_t maj, min;
41 	uint8_t it, pats, gv;
42 	char reserved[13];
43 } FileHeader;
44 #endif
45 
DumpPrefix(unsigned char * mem,int len,int base,int baselen)46 void DumpPrefix (unsigned char *mem, int len, int base, int baselen)
47 {
48 	int i;
49 	printf ("[%s%08x%s]%s", FONT_BRIGHT_BLUE, base, FONT_RESET, FONT_BRIGHT_PURPLE);
50 	for (i=0; i < baselen; i++)
51 	{
52 		if (base+i >= len)
53 		{
54 			printf (" \?\?");
55 		} else {
56 			printf (" %02x", mem[base+i]);
57 		}
58 	}
59 	switch (baselen)
60 	{
61 		case 2:  printf (                  "%s ", FONT_RESET); break;
62 		case 1:  printf (               "%s    ", FONT_RESET); break;
63 		case 0:  printf (            "%s       ", FONT_RESET); break;
64 		default: printf ("%s\n                 ", FONT_RESET); break;
65 	}
66 }
67 
DumpInstrument(unsigned char * mem,int len,int base,int instrument)68 int DumpInstrument (unsigned char *mem, int len, int base, int instrument)
69 {
70 	uint16_t ParaPtr;
71 	uint16_t Length;
72 	uint16_t LoopStart;
73 	uint16_t LoopEnd;
74 	uint16_t C3Spd;
75 	uint16_t LengthPara;
76 	int i;
77 
78 	printf ("[%sINSTRUMENT %02d / PCM Sample%s]\n", FONT_BRIGHT_CYAN, instrument + 1, FONT_RESET);
79 
80 	DumpPrefix (mem, len, base + 0x00, 12);
81 	if ((base + 31) >= len)
82 	{
83 		fprintf (stderr, "\n%sERROR: Ran out of data (I #1)%s\n", FONT_BRIGHT_RED, FONT_RESET);
84 		return -1;
85 	}
86 	printf ("FileName: \"");
87 	for (i=0; i < 12; i++)
88 	{
89 		if (!mem[base + 0x00 + i])
90 		{
91 			break;
92 		}
93 		putchar (mem[base + 0x00 + i]);
94 	}
95 	printf("\"\n");
96 
97 
98 	DumpPrefix (mem, len, base + 0x0c, 1);
99 	if ((base + 0x0c) >= len)
100 	{
101 		fprintf (stderr, "\n%sERROR: Ran out of data (I #2)%s\n", FONT_BRIGHT_RED, FONT_RESET);
102 		return -1;
103 	}
104 	printf ("Type: %s%s%s\n",
105 		(mem[base+0x0c] == 0x00) ? FONT_BRIGHT_GREEN : FONT_BRIGHT_RED,
106 		(mem[base+0x0c] == 0x00) ? "PCM Sample" : "Unknown",
107 		FONT_RESET);
108 
109 
110 	DumpPrefix (mem, len, base + 0x0d, 1);
111 	if ((base + 0x0d) >= len)
112 	{
113 		fprintf (stderr, "\n%sERROR: Ran out of data (I #3)%s\n", FONT_BRIGHT_RED, FONT_RESET);
114 		return -1;
115 	}
116 	printf ("Disk: %d\n", mem[base+0x0d]);
117 
118 
119 	DumpPrefix (mem, len, base + 0x0e, 2);
120 	if ((base + 0x0e) >= len)
121 	{
122 		fprintf (stderr, "\n%sERROR: Ran out of data (I #4)%s\n", FONT_BRIGHT_RED, FONT_RESET);
123 		return -1;
124 	}
125 	ParaPtr = uint16_little (((uint16_t *)(mem + base + 0x0e))[0]);
126 	printf ("MemSeg: paraptr 0x%04x => 0x%08x\n", ParaPtr, ParaPtr << 4);
127 	Instruments[instrument].offset = ParaPtr << 4;
128 
129 
130 	DumpPrefix (mem, len, base + 0x10, 2);
131 	if ((base + 0x10 + 1) >= len)
132 	{
133 		fprintf (stderr, "\n%sERROR: Ran out of data (I #5)%s\n", FONT_BRIGHT_RED, FONT_RESET);
134 		return -1;
135 	}
136 	Length = uint16_little (((uint16_t *)(mem + base + 0x10))[0]);
137 	printf ("Length:     %d %s%s%s\n", (int)Length, Length>64000 ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN, (Length>64000) ? " Sample too long, will be cropped at 64000" : "", FONT_RESET);
138 	Instruments[instrument].length = Length;
139 
140 
141 	DumpPrefix (mem, len, base + 0x12, 2);
142 	if ((base + 0x12 + 1) >= len)
143 	{
144 		fprintf (stderr, "\n%sERROR: Ran out of data (I #6)%s\n", FONT_BRIGHT_RED, FONT_RESET);
145 		return -1;
146 	}
147 	LoopStart = uint16_little (((uint16_t *)(mem + base + 0x12))[0]);
148 	printf ("Loop-Start: %d %s%s%s\n", (int)LoopStart, (LoopStart>Length) ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN, (LoopStart>Length) ? " LoopStart > Length" : "", FONT_RESET);
149 
150 
151 	DumpPrefix (mem, len, base + 0x14, 2);
152 	if ((base + 0x14 + 1) >= len)
153 	{
154 		fprintf (stderr, "\n%sERROR: Ran out of data (I #7)%s\n", FONT_BRIGHT_RED, FONT_RESET);
155 		return -1;
156 	}
157 	LoopEnd = uint16_little (((uint16_t *)(mem + base + 0x14))[0]);
158 	printf ("Loop-End: %d %s%s%s\n", (int)LoopEnd,
159 		((LoopEnd>(Length+1)) && (LoopEnd != 0xffff)) ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN,
160 		((LoopEnd>(Length+1)) && (LoopEnd != 0xffff)) ? " LoopEnd > Length + 1" : (LoopEnd == 0xffff) ? "No loop" : "", FONT_RESET);
161 
162 
163 	DumpPrefix (mem, len, base + 0x16, 1);
164 	if ((base + 0x16) >= len)
165 	{
166 		fprintf (stderr, "\n%sERROR: Ran out of data (I #8)%s\n", FONT_BRIGHT_RED, FONT_RESET);
167 		return -1;
168 	}
169 	printf ("Volume: %d %s%s%s\n", mem[base+0x16], (mem[base+0x16] > 64) ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN, (mem[base+0x16] > 64) ? " This is greater than 64" : "", FONT_RESET);
170 
171 
172 	DumpPrefix (mem, len, base + 0x17, 1);
173 	if ((base + 0x17) >= len)
174 	{
175 		fprintf (stderr, "\n%sERROR: Ran out of data (I #9)%s\n", FONT_BRIGHT_RED, FONT_RESET);
176 		return -1;
177 	}
178 	printf ("Reserved/unused\n");
179 
180 
181 	DumpPrefix (mem, len, base + 0x18, 2);
182 	if ((base + 0x18+1) >= len)
183 	{
184 		fprintf (stderr, "\n%sERROR: Ran out of data (I #10)%s\n", FONT_BRIGHT_RED, FONT_RESET);
185 		return -1;
186 	}
187 	C3Spd = uint32_little (((uint16_t *)(mem + base + 0x18))[0]);
188 	printf ("C3 Sample Rate: %d\n", C3Spd);
189 
190 
191 	DumpPrefix (mem, len, base + 0x1a, 4);
192 	if ((base + 0x1a + 3) >= len)
193 	{
194 		fprintf (stderr, "\n%sERROR: Ran out of data (I #11)%s\n", FONT_BRIGHT_RED, FONT_RESET);
195 		return -1;
196 	}
197 	printf ("Reserved / Internal use / leave at 0\n");
198 
199 
200 	DumpPrefix (mem, len, base + 0x1e, 2);
201 	if ((base + 0x1e + 1) >= len)
202 	{
203 		fprintf (stderr, "\n%sERROR: Ran out of data (I #12)%s\n", FONT_BRIGHT_RED, FONT_RESET);
204 		return -1;
205 	}
206 	LengthPara = uint16_little (((uint16_t *)(mem + base + 0x1e))[0]);
207 	printf ("Length-Para: %d (not used)\n", LengthPara);
208 
209 	return 0;
210 }
211 
print_note(unsigned char note)212 void print_note (unsigned char note)
213 {
214 	char *text[16] = {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-", "?c", "?d", "?e", "?f"};
215 
216 	if (note == 0xfe)
217 	{
218 		printf ("-0-");
219 		if (savepatterns)
220 		{
221 			fprintf (savepatterns, "-0-");
222 		}
223 		return;
224 	}
225 	if (note >= 0x60)
226 	{
227 		printf ("...");
228 		if (savepatterns)
229 		{
230 			fprintf (savepatterns, "...");
231 		}
232 		return;
233 	}
234 
235 	if ((note & 0x0f) >= 12) printf ("%s", FONT_BRIGHT_RED);
236 	printf ("%s", text[note & 0x0f]);
237 	if (savepatterns)
238 	{
239 		fprintf (savepatterns, "%s", text[note & 0x0f]);
240 	}
241 	if ((note & 0x0f) >= 12) printf ("%s", FONT_RESET);
242 
243 	printf ("%d", note >> 4);
244 	if (savepatterns)
245 	{
246 		fprintf (savepatterns, "%d", note>>4);
247 	}
248 }
249 
DumpPattern(unsigned char * mem,int len,int base,int pattern)250 int DumpPattern (unsigned char *mem, int len, int base, int pattern)
251 {
252 	int offset = 0;
253 	int i;
254 
255 	printf ("[%sPATTERN %d%s]\n", FONT_BRIGHT_CYAN, pattern, FONT_RESET);
256 	if (savepatterns)
257 	{
258 		fprintf (savepatterns, "PATTERN %d\n", pattern);
259 	}
260 
261 	for (i=0; i < 64; i++)
262 	{
263 		int j;
264 
265 		do {
266 			int preoffset = offset; /* so we can rewind */
267 
268 			for (j=0; j < 4; j++)
269 			{
270 				if (base+preoffset >= len)
271 				{
272 					if (offset != len)
273 					{
274 						DumpPrefix (mem, len, base + offset, len - offset);
275 					}
276 					fprintf (stderr, "\n%sERROR: Ran out of data (P #1)%s\n", FONT_BRIGHT_RED, FONT_RESET);
277 					return -1;
278 				}
279 				switch (mem[base + preoffset])
280 				{
281 					case 0xfb:
282 					case 0xfc:
283 					case 0xfd:
284 						preoffset += 1;
285 						break;
286 					default:
287 						preoffset += 4;
288 						if ((base + preoffset - 1) >= len)
289 						{
290 							if (offset != len)
291 							{
292 								DumpPrefix (mem, len, base + offset, len - offset);
293 							}
294 							fprintf (stderr, "\n%sERROR: Ran out of data (P #2)%s\n", FONT_BRIGHT_RED, FONT_RESET);
295 							return -1;
296 						}
297 						break;
298 				}
299 			}
300 
301 			DumpPrefix (mem, len, base + offset, preoffset - offset);
302 		} while (0);
303 
304 		printf ("%02X |", i);
305 		if (savepatterns)
306 		{
307 			fprintf (savepatterns, "%02X |", i);
308 		}
309 
310 		for (j=0; j < 4; j++)
311 		{
312 			uint8_t note, insvol, volcmd, cmdinf;
313 			switch (mem[base+offset])
314 			{
315 				case 0xfb:
316 					offset += 1;
317 					note = insvol = volcmd = cmdinf = 0x00;
318 					break;
319 				case 0xfc:
320 					offset += 1;
321 					printf (" ... .. .. .00 |");
322 					if (savepatterns)
323 					{
324 						fprintf (savepatterns, " ... .. .. .00 |");
325 					}
326 					goto next;
327 				case 0xfd: offset += 1; printf(" -0- .. .. .00 |"); goto next;
328 				default:   note=mem[base + offset++]; insvol=mem[base + offset++]; volcmd=mem[base + offset++]; cmdinf=mem[base + offset++]; break;
329 			}
330 
331 			printf (" ");
332 			if (savepatterns)
333 			{
334 				fprintf (savepatterns, " ");
335 			}
336 
337 			print_note(note);
338 
339 			printf (" ");
340 			if (savepatterns)
341 			{
342 				fprintf (savepatterns, " ");
343 			}
344 
345 			if ((insvol >> 3) == 0)
346 			{
347 				printf ("..");
348 				if (savepatterns)
349 				{
350 					fprintf (savepatterns, "..");
351 				}
352 			} else {
353 				printf ("%02d", insvol>>3);
354 				if (savepatterns)
355 				{
356 					fprintf (savepatterns, "%02d", insvol>>3);
357 				}
358 			}
359 
360 			printf (" ");
361 			if (savepatterns)
362 			{
363 				fprintf (savepatterns, " ");
364 			}
365 
366 			if (((insvol & 0x07) | ((volcmd & 0xf0) >> 1)) > 64)
367 			{
368 				printf ("..");
369 				if (savepatterns)
370 				{
371 					fprintf (savepatterns, "..");
372 				}
373 			} else {
374 				printf ("%02d", (insvol & 0x07) | ((volcmd & 0xf0) >> 1));
375 				if (savepatterns)
376 				{
377 					fprintf (savepatterns, "%02d", (insvol & 0x07) | ((volcmd & 0xf0) >> 1));
378 				}
379 			}
380 
381 			printf (" ");
382 			if (savepatterns)
383 			{
384 				fprintf (savepatterns, " ");
385 			}
386 
387 			printf ("%c%02X |", ".ABCDEFGHIJKLMNO"[volcmd & 0x0f], cmdinf);
388 			if (savepatterns)
389 			{
390 				fprintf (savepatterns, "%c%02X |", ".ABCDEFGHIJKLMNO"[volcmd & 0x0f], cmdinf);
391 			}
392 
393 			next: {};
394 		}
395 
396 		printf ("\n");
397 		if (savepatterns)
398 		{
399 			fprintf (savepatterns, "\n");
400 		}
401 	}
402 
403 	return offset;
404 }
405 
DumpHeader(unsigned char * mem,int len)406 int DumpHeader (unsigned char *mem, int len)
407 {
408 	int i, j;
409 
410 	if (len < 0x30)
411 	{
412 		fprintf (stderr, "%sERROR: len < sizeof(FileHeader)%s\n", FONT_BRIGHT_RED, FONT_RESET);
413 		return 1;
414 	}
415 
416 	printf ("[%sHEADER%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
417 
418 	/* hdr.name */
419 	DumpPrefix (mem, len, 0x00, 20);
420 	printf ("Name: \"");
421 	for (i=0; i < 20; i++)
422 	{
423 		if (!mem[0x00+i])
424 			break;
425 		printf ("%c", (char)mem[0x00+i]);
426 	}
427 	printf ("\"\n");
428 
429 	DumpPrefix (mem, len, 0x14, 8);
430 	printf ("Tracker: \"");
431 	j=0;
432 	for (i=0; i < 8; i++)
433 	{
434 		if ((mem[0x14+i] < 0x20) || (mem[0x14+i] >= 0x80))
435 		{
436 			j = 1;
437 		}
438 	}
439 	for (i=0; i < 8; i++)
440 	{
441 		if (!mem[0x14+i])
442 			break;
443 		printf ("%c", (char)mem[0x14+i]);
444 	}
445 	printf ("\" %s%s%s\n",
446 		j ? FONT_BRIGHT_RED : FONT_BRIGHT_GREEN,
447 		j ? "Non-ASCII" : "OK",
448 		FONT_RESET);
449 
450 	DumpPrefix (mem, len, 0x1c, 1);
451 	printf ("Signature: %s%s%s\n",
452 		(mem[0x1c] == 0x1A) ? FONT_BRIGHT_GREEN : (mem[0x1c] == 0x02) ? FONT_BRIGHT_YELLOW : FONT_BRIGHT_RED,
453 		(mem[0x1c] == 0x1A) ? "OK" : (mem[0x1c] == 0x02) ? "Known invalid value" : "Failed!!!!",
454 		FONT_RESET);
455 
456 	DumpPrefix (mem, len, 0x1d, 1);
457 	printf ("Type: ");
458 	switch (mem[0x1d])
459 	{
460 		case  1: printf ("STM song w/o samples\n"); break;
461 		case  2: printf ("STM module\n"); break;
462 		case 16: printf ("S3M module, FAILED !!!!!\n"); return 1;
463 		default: printf ("Unknown, FAILED !!!!!\n"); return 1;
464 	}
465 
466 	DumpPrefix (mem, len, 0x1e, 2);
467 	printf ("Version: %d.%d\n", mem[0x1e], mem[0x1f]);
468 
469 	DumpPrefix (mem, len, 0x20, 1);
470 	printf ("Initial Tempo: %d\n", mem[0x20]);
471 
472 	DumpPrefix (mem, len, 0x21, 1);
473 	printf ("Patterns: %d\n", mem[0x21]);
474 
475 	DumpPrefix (mem, len, 0x22, 1);
476 	printf ("Global Volume: %d\n", mem[0x22]);
477 
478 	DumpPrefix (mem, len, 0x23, 13);
479 	printf ("(Reserved/not used)\n");
480 
481 	return 0;
482 }
483 
DumpOrders(unsigned char * mem,int len,int count,int pats)484 int DumpOrders (unsigned char *mem, int len, int count, int pats)
485 {
486 	int i;
487 
488 	printf ("[%sORDERS%s]\n", FONT_BRIGHT_CYAN, FONT_RESET);
489 	for (i=0; i < count; i++)
490 	{
491 		if ((i&15) != 0)
492 		{
493 			putchar (' ');
494 		} else {
495 			DumpPrefix (mem, len, 0x410 + i, 16);
496 			if ((0x410 + i + 16) > len)
497 			{
498 				fprintf (stderr, "\n%sERROR: Ran out of data (S #1)%s\n", FONT_BRIGHT_RED, FONT_RESET);
499 				return -1;
500 			}
501 		};
502 
503 		if ( mem[0x410+i]==99 )
504 		{
505 			printf ("99(ignore)");
506 		} else if (mem[0x410+i]==255)
507 		{
508 			printf ("255(EOS)"); // End Of Song
509 		} else if (mem[0x410+i]>=pats)
510 		{
511 			printf("%s%d(out of range)%s", FONT_BRIGHT_RED, mem[0x410+i], FONT_RESET);
512 		} else {
513 			printf ("%d", mem[0x410+i]);
514 		}
515 		if ((i&15) == 15)
516 		{
517 			putchar ('\n');
518 		}
519 	}
520 	if ((i&15) != 0)
521 	{
522 		printf ("\n");
523 	}
524 
525 	return 0;
526 }
527 
ParseSTM(unsigned char * mem,int len)528 int ParseSTM (unsigned char *mem, int len)
529 {
530 	int i;
531 	int patternlen = 0;
532 
533 	if (DumpHeader (mem, len))
534 	{
535 		return -1;
536 	}
537 
538 	for (i=0; i < 31; i++)
539 	{
540 		if (DumpInstrument (mem, len, 0x30 + i*0x20, i))
541 		{
542 			return -1;
543 		}
544 	}
545 
546 	if (DumpOrders (mem, len, mem[0x1f]?128:64, mem[0x21]))
547 	{
548 		return -1;
549 	}
550 
551 	for (i=0; i < mem[0x21]; i++)
552 	{
553 		int retval = DumpPattern (mem, len, 0x30 + 0x20*31 + (mem[0x1f]?128:64) + patternlen, i);
554 		if (retval < 0)
555 		{
556 			return -1;
557 		}
558 		patternlen += DumpPattern (mem, len, 0x30 + 0x20*31 + (mem[0x1f]?128:64) + patternlen, i);
559 	}
560 	if (savepatterns)
561 	{
562 		fclose (savepatterns);
563 	}
564 
565 	for (i=0; i < 31; i++)
566 	{
567 		if (Instruments[i].length > 0)
568 		{
569 			printf ("[%sINSTRUMENT %02x SAMPLE DATA%s]\n", FONT_BRIGHT_CYAN, i + 1, FONT_RESET);
570 
571 			printf ("[%s%08x-%08x%s]%s\n", FONT_BRIGHT_BLUE, Instruments[i].offset, Instruments[i].offset + Instruments[i].length - 1, FONT_RESET, FONT_RESET);
572 			if (savesamples)
573 			{
574 				if ((Instruments[i].offset + Instruments[i].length) > len)
575 				{
576 					printf ("%sWARNING: Unable to store instrument %d, missing data\n%s", FONT_BRIGHT_YELLOW, i + 1, FONT_RESET);
577 				} else {
578 					char filename[33];
579 					int fd;
580 					snprintf (filename, sizeof (filename), "Instrument %02d.signed 8bit.sample", i+1);
581 					fd = open (filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
582 					if (fd < 0)
583 					{
584 						printf ("%sWARNING: Unable to open %s%s\n", FONT_BRIGHT_YELLOW, filename, FONT_RESET);
585 					} else {
586 						write (fd, mem + Instruments[i].offset, Instruments[i].length);
587 						close (fd);
588 						printf ("Saved %s\n", filename);
589 					}
590 				}
591 			}
592 		}
593 	}
594 
595 	return 0;
596 }
597 
598 
main(int argc,char * argv[])599 int main(int argc, char *argv[])
600 {
601 	struct stat st;
602 	size_t ps = sysconf(_SC_PAGE_SIZE);
603 	int fd;
604 	size_t data_mmaped_len;
605 	unsigned char *data;
606 	int c;
607 	char *color = "auto";
608 	int help = 0;
609 
610 	while (1)
611 	{
612 		int option_index = 0;
613 		static struct option long_options[] =
614 		{
615 			{"color",        optional_argument, 0, 0},
616 			{"help",         no_argument,       0, 'h'},
617 			{"savepatterns", no_argument,       0, 'p'},
618 			{"savesamples",  no_argument,       0, 's'},
619 			{0,              0,                 0, 0}
620 		};
621 
622 		c = getopt_long(argc, argv, "hsp", long_options, &option_index);
623 		if (c == -1)
624 			break;
625 
626 		switch (c)
627 		{
628 			case 0:
629 				if (option_index == 0)
630 				{
631 					color = optarg;
632 				}
633 				break;
634 			case 'p':
635 				if (!savepatterns)
636 				{
637 					savepatterns = fopen ("patterns.txt", "w");
638 					if (!savepatterns)
639 					{
640 						fprintf (stderr, "Unable to open patterns.txt for writing: %s\n", strerror (errno));
641 						return 1;
642 					}
643 				}
644 				break;
645 			case 's':
646 				savesamples = 1;
647 				break;
648 			case 'h':
649 				help = 1;
650 				break;
651 			case '?':
652 				help = 3;
653 				break;
654 			default:
655 				printf("?? getopt returned character code 0%o ??\n", c);
656 		}
657 	}
658 
659 	if (optind != (argc-1))
660 	{
661 		help = 4;
662 	}
663 
664 	if (!color)
665 	{
666 		usecolor = 1;
667 	} else if (!strcmp (color, "auto"))
668 	{
669 		usecolor = isatty ( 1 );
670 	} else if ((strcmp (color, "never")) && (strcmp (color, "no")))
671 	{
672 		usecolor = 1;
673 	} else {
674 		usecolor = 0;
675 	}
676 
677 	if (help)
678 	{
679 		fprintf (stderr, "Usage:\n%s [--color=auto/never/on] [--savesamples -s] [--savepatterns -p] [--help] file.stm  (%d)\n", argv[0], help);
680 		return 1;
681 	}
682 
683 	fd = open (argv[optind], O_RDONLY);
684 	if (fd < 0)
685 	{
686 		perror ("open()");
687 		return 0;
688 	}
689 	if (fstat(fd, &st))
690 	{
691 		perror("fstat()");
692 		close (fd);
693 		return 0;
694 	}
695 	if (!st.st_size)
696 	{
697 		fprintf (stderr, "Zero-size file\n");
698 		close (fd);
699 		return 0;
700 	}
701 
702 //	s.data_len = st.st_size;
703 	data_mmaped_len = roundup (st.st_size, ps);
704 	data = mmap (0, data_mmaped_len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
705 
706 	if (data == MAP_FAILED)
707 	{
708 		perror ("mmap() failed");
709 		close (fd);
710 		return 0;
711 	}
712 
713 	if (usecolor)
714 	{
715 		FONT_RESET         = "\033[0m";
716 		FONT_BRIGHT_BLACK  = "\033[30;1m";
717 		FONT_BRIGHT_RED    = "\033[31;1m";
718 		FONT_BRIGHT_GREEN  = "\033[32;1m";
719 		FONT_BRIGHT_YELLOW = "\033[33;1m";
720 		FONT_BRIGHT_BLUE   = "\033[34;1m";
721 		FONT_BRIGHT_PURPLE = "\033[35;1m";
722 		FONT_BRIGHT_CYAN   = "\033[36;1m";
723 	}
724 
725 	if (ParseSTM (data, st.st_size))
726 	{
727 		goto failed;
728 	}
729 
730 failed:
731 	munmap (data, data_mmaped_len);
732 	close (fd);
733 	return 0;
734 }
735