FreeCalypso > hg > freecalypso-reveng
diff fluid-mnf/fluid.c @ 311:9cecc930d78f
fluid-mnf: original source from TI,
defenestrated line endings and rearranged directory structure,
but no *.[ch] source file content changes yet
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 29 Feb 2020 05:36:07 +0000 |
parents | |
children | 77c86062e253 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fluid-mnf/fluid.c Sat Feb 29 05:36:07 2020 +0000 @@ -0,0 +1,818 @@ +/****************************************************************************** + * FLUID (Flash Loader Utility Independent of Device) + * + * Copyright Texas Instruments, 2001. + * Mads Meisner-Jensen, mmj@ti.com. + * + * Main, command-line argument parsing, error handling. + * + * $Id: fluid.c 1.50 Thu, 14 Nov 2002 13:10:05 +0100 tsj $ + * + ******************************************************************************/ + +#include "fluid.h" +#include "flash.h" +#include "fileio.h" +#include "trace.h" +// Secure Calypso Plus +#include "../inc/ram_load.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#if defined(MSC) || defined(BCC) + #include "getopt.h" + #include "windows.h" +#else + #include <getopt.h> +#endif + +#include <errno.h> // for ERANGE + + +/****************************************************************************** + * Prototypes and Globals + ******************************************************************************/ + +extern T_RAM_LOADER d_ram_loader; // Secure Calypso Plus + +char *arg_file_list[ARG_FILE_LIST_SIZE_MAX] = { (char *) 0 }; +int arg_file_list_size = 0; + +char *arg_erase_override = ""; +char *arg_read = ""; +char *arg_write = ""; +int arg_checksum = 1; +int arg_compress = 1; +int arg_dry_run = 0; +int arg_list_devices = 0; +char arg_target_type = 0; +int arg_image_map_show = 0; +int arg_sector_map_show = 0; +int arg_sector_list_show = 0; +int arg_timers_show = 0; +int arg_timers_extended_show = 0; +int arg_checksum_show = 0; +int arg_show_hexdump = 0; +int arg_target_trace_enable = 0; +int arg_progress = 'a'; +char arg_hexfile_type = 'm'; +char arg_hexfile_memwidth = 2; + +int arg_target_reset = 1; +int arg_rom_bootloader = 0; +int arg_boot_delay_rom = 15; +int arg_boot_delay_fluid = 15; +int arg_device_id0 = -1; +int arg_device_id1 = -1; + +int arg_uart_port = 1; +int arg_uart_baudrate = 115200; +char arg_uart_flowcontrol[] = "pn"; +char arg_uart_level_convert = 0; + +char arg_verbose = 0; +int arg_debug_resume = 0; +int arg_debug_trace_pe = 0; +int arg_keep_going = 0; +int arg_show_main_args = 0; +int arg_skip_erase = 0; + +// Secure Calypso Plus +char *arg_die_id_file_name = ""; +char *arg_imeisv = ""; +char *arg_platform_certificate_addr = ""; +int arg_request_certificate = 0; +int arg_delay_for_changing_cs5 = 0; +int arg_uart_baudrate_during_cmd_download = 115200; +int arg_uart_timeout_configuration = 0; +int arg_block_size = 8 * 1024; // Must be a modulus of 64 bytes, except for the last command. + +int arg_usage = 0; + +char *argv_0; + +int arg_tr_mask = 0; +int arg_tr_spaces = 2; +char *arg_tr_file = NULL; + +int arg_errorfd = 2; + +static void main_usage(void); +static void main_args(int argc, char *argv[]); +static long arg_long_get(void); + +extern int fluid_machine(void); +extern int fluid_compress(void); +extern int fluid_decompress(void); + +extern int serial_is_baudrate(int bps); + + +/****************************************************************************** + * Error handling + ******************************************************************************/ + +extern char *main_strerror(int error); + +char *win32_strerror(void) +{ + static char buf[220]; + int error; + char *p = buf; + + error = GetLastError(); + p += sprintf(buf, "%d: ", error); + + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + p, sizeof(buf) - 20, NULL) == 0) + sprintf(p, "(Unknown Win32 error)"); + + return buf; +} + +void main_msg(char *format, ...) +{ + va_list args; + char buf[1024]; + + va_start(args, format); + vsprintf(buf, format, args); + va_end(args); + + if (arg_errorfd == 2) { + fprintf(stderr, "%s", buf); + fflush(stderr); + } + else { + fprintf(stdout, "%s", buf); + fflush(stdout); + } +} + +void main_error_str(char type, int error, char *string) +{ + // If it was an OS error... + if (error < E_OS) { + error -= E_OS; + main_msg("OS-ERROR: %s", win32_strerror()); + } + + main_msg(" %s(%d): %s%s\n", (type == 'w' ? "WARNING" : "ERROR"), + -error, main_strerror(error), string); +} + +void main_warning(int error) +{ + main_error_str('w', error, ""); +} + +void main_error(int error) +{ + main_error_str('e', error, ""); + + if (arg_keep_going == 0) + exit(-error); +} + +void main_fatal(int error) +{ + main_error(error); + exit(-error); +} + + +/****************************************************************************** + * Command line parsing + ******************************************************************************/ + +static void main_help(void) +{ + printf( + "\n" + "You have started fluid with no command line arguments\n" + "\n" + "To see all the available command line arguments, start fluid\n" + "from a command line prompt (cmd.exe or similar) with:\n" + "\n" + " fluid -h\n" + "\n" + "To see some basic and common examples of usage, start fluid with:\n" + "\n" + " fluid -ic\n" + "\n" + "You can get an overview of all the available examples with:\n" + "\n" + " fluid -ii\n" + "\n" +// "Please read the README file for notes and other info and read the\n" +// "HISTORY file to see what has happened with fluid since last release.\n" +// "\n" + "Press RETURN to exit...\n" + ); + getchar(); +} + +static void main_example(int type) +{ + switch (type) { + case 'c': + printf( + "Download into board:\n" + " fluid -f gsm.m0\n" + "\n" + "Simulate a download into board (dry-run):\n" + " fluid -n -f gsm.m0\n" + "\n" + "Check if file has already been downloaded into board:\n" + " fluid -n -f gsm.m0\n" + "\n" + "Download into board without erasing boot sector:\n" + " fluid -e-0 -f gsm.m0\n" + "\n" + "Download into board with another progress indication:\n" + " fluid -gc -f gsm.m0\n" + "\n" + ); + break; + case 'a': + printf( + "Download into board with more output verbosity:\n" + " fluid -v -v -f gsm.m0\n" + "\n" + "Show the image map (which parts of the flash are used, which are not):\n" + " fluid -si -n -f gsm.m0\n" + "\n" + "Show both the image and the erase maps:\n" + " fluid -sis -n -f gsm.m0\n" + "\n" + "Download into board without delta download:\n" + " fluid -C -f gsm.m0\n" + "\n" + ); + break; + case 'e': + printf( + "Erase all flash (including boot sector!):\n" + " fluid -e+*\n" + "\n" + "Erase all flash except the boot sector:\n" + " fluid -e+*,-0\n" + "\n" + "Erase the last megabyte of a 4MB flash device:\n" + " fluid -e+3M..4M\n" + "\n" + "Erase all flash except sectors 1..7 and addresses 1984k..2048k:\n" + " fluid -e+*,-1..8,-1984k..2048k\n" + "\n" + ); + break; + case 'r': + printf( + "Read whole FFS system from a B-Sample:\n" + " fluid -r3M..4M -f bsffs.m0\n" + "\n" + "Then copy/download it (e.g., to another B-Sample):\n" + " fluid -f bsffs.m0\n" + "\n" + "Read serial switch config from a B- or C-Sample:\n" + "(serial switch config is in sector 2 on TI releases earlier than SSA-5.3.1)\n" + " fluid -r0x11ffe..0x12000 -f usxx.m0 -sx\n" + "\n" + "Copy it to a(nother) B- or C-sample:\n" + " fluid -f usxx.m0\n" + "\n"); + break; + case 'w': + printf( + "Over-write image with a byte string at a specific address:\n" + " fluid -f gsm.m0 -w7800=0x11,0x22,0x33,0x44,0x55,0x66\n" + "\n" + "Write zeroes into top-most 2MB of C-Sample flash memory:\n" + " fluid -w2M..4M=0\n" + "\n" + "Write a string to a specific address:\n" + " fluid -w0x1800=\"\"\"Mads\"\"\",0\n" + "\n"); + break; + case 's': + printf( + "Reset target, doing nothing else (requires special cable):\n" + " fluid -n -or\n" + "\n" + ); + break; + default: + printf( + "Avaliable examples:\n" + " a = Advanced, common usage\n" + " c = Common usage\n" + " e = Erase override\n" + " r = Read target memory\n" + " w = Write target memory\n" + " s = Special usage\n" + ); + break; + } + exit(0); +} + +static void main_debug_usage(void) +{ + printf("Debug usage: fluid [OPTIONS...]\n" + "\n" + " -d r Display target (remote) tracing.\n" + " -d c Resume fluid state machine in command interpreter.\n" + " -d o Display final command line option values.\n" + " -d t<char> Trace mask in human format:\n" + " a = All, except ?\n" + " * = All\n" + " g = getchar()\n" + " p = putchar()\n" + " G = target driver receive\n" + " P = target driver transmit\n" + " w = target wait\n" + " t = target/transport layer driver\n" + " h = hexfile read/decode\n" + " H = hexfile write/encode\n" + " r = device file parser\n" + " c = Command line argument parser\n" + " u = utility functions\n" + " m = state machine functions\n" + " \n" + " -d v Display info on compiler used.\n" + " -d f<file> Trace to file.\n" + " -d i<n> Trace indentation multiplier. Default is 2.\n" + " -d m<n> Trace mask. Default is 0.\n" + " -t <char> Trace mask in human format. Same as '-d t<char>'.\n" + "\n" + "B-/C-/D-Sample LEDs layout:\n" + "\n" + "+---0---+---1---+---2---+---3---+---4---+---5---+---6---+---7---+\n" + "| Recv | Erase | Prog | Overhd| Idle | | | Busy |\n" + "+-------+-------+-------+-------+-------+-------+-------+-------+\n" + ); + exit(0); +} + +static void main_args_debug_trace(void) +{ + while (*optarg) { + switch(*optarg++) { + case 'a': arg_tr_mask |= TrAll & ~(0); break; + case '*': arg_tr_mask |= TrAll; break; + case 'm': arg_tr_mask |= TrMachines; break; + case 'g': arg_tr_mask |= TrGetChar; break; + case 'p': arg_tr_mask |= TrPutChar; break; + case 'G': arg_tr_mask |= TrDriverGet; break; + case 'P': arg_tr_mask |= TrDriverPut; break; + case 'w': arg_tr_mask |= TrTargetWait; break; + case 't': arg_tr_mask |= TrTargetDrv; break; + case 'h': arg_tr_mask |= TrHexRead; break; + case 'H': arg_tr_mask |= TrHexWrite; break; + case 'r': arg_tr_mask |= TrParser; break; + case 'c': arg_tr_mask |= TrArgParser; break; + case 'C': arg_tr_mask |= TrCmdLineParser; break; + case 'u': arg_tr_mask |= TrUtility; break; + } + } +} + +static void fluid_welcome(void) +{ + flowf(NORMAL, + "FLUID Revision 2.27, (23 Aug 2004). Copyright Texas Instruments, 2001-2004.\n"); +} + +static void fluid_compile_info(void) +{ + flowf( + NORMAL, + "Compiled " __DATE__ " " __TIME__ " with " +#if defined(MSC) + "Microsoft cl.exe" +#elif defined(BCC) + "Borland bcc" +#else + "GNU gcc" +#endif + "\n"); +} + +static void main_usage(void) +{ + printf( + "Usage: fluid [OPTIONS...]\n" + "\n"); + if (!arg_usage) + fluid_welcome(); + printf( + "FLUID is a Flash Loader Utility Independent of Device\n" + "This version supports:\n" + " TI GSM Boot Loader V6.x.x (with fluid patch)\n" + " TI ROM Boot Loader (Calypso devices only)\n" + "\n" + " -f <file> Flash image file (input or output file).\n" + " -p <num> Serial port number. Default is 1.\n" + " -b <num> Serial baudrate. Default is 115200.\n" + " -t <char> Target type (Default is auto-detect):\n" + " h = Hercules\n" + " u = Ulysses\n" + " c = Calypso\n" + " l = Calypso Lite\n" + " p = Calypso Plus\n" + " -l List all known flash devices.\n" + " -c, -C Do or do not checksum target memory thus enabling delta\n" + " download (only program changed sectors). Default is on.\n" + " -z, -Z Do or do not compress data on download. Default is on.\n" + " -g <char> Progress indication type:\n" + " a = asterisks (default), c = chars, d = dots,\n" + " x = address+size, n = none\n" + " -e [+|-]<addr0>..<addr1>,... or [+|-]<n>,...<\n" + " Erase/program override. Erase or don't erase flash\n" + " memory in the range [addr0..addr1[. Use '-ie' to see\n" + " examples of usage\n" + " -<...> = do *not* erase and program\n" + " +<...> = force erase\n" + " Giving <n> as an asterisk, '*', means all sectors\n" + " -r <addr0>..<addr1>,...\n" + " Read target memory range [addr0..addr1[ and write the\n" + " bytes to output file specified.\n" + " -w <addr0>..<addr1>=<b0,b1,...,bN>:...\n" + " Write bytes to image. The bytes b0..bN are replicated\n" + " through the whole memory range [addr0..addr1[\n" + " -o <char> Extra options:\n" + " o = Only bootstrap using ROM boot loader (Calypso devices only)\n" + " O = Do NOT use ROM boot loader\n" + " e = Skip erase (Require empty flash)\n" + " r = Reset target after download (default)\n" + " R = Do NOT reset target after download\n" + " l = Activate (old-fashioned) UART level conversion\n" + " m = Select Motorola hexfile output format (default)\n" + " b = Select binary/raw file output format\n" + " i<n1>,<n2> = Disable device auto-detection and set manufacturer\n" + " id and device id\n" + " d<n1>,<n2> = Set detection delay (in ms) for ROM and fluid boot\n" + " loader, respectively\n" + " 1, 2, 4 = Select hexfile memory width 1, 2 or 4. Default is 2\n" + " -s <char> Show additional info:\n" + " i = image map\n" + " s = sector erase map\n" + " l = sector erase list\n" + " t = target timers, T = extended target timer info\n" + " x = hexdump of target memory (together with '-r')\n" + " c = checksums\n" + " -n Dry run. Do not program the flash device.\n" + " -v Be verbose. Multiple '-v's means more verbosity.\n" + " -q Be quiet.\n" +// " -y Use stdout for error messages.\n" + " -dh Display help on debug and trace options.\n" + " -h Display this help.\n" + " -i <char> Display examples (i = index/overview of examples).\n" + // Secure Calypso Plus + "\n Secure Calypso Plus options:\n" + " -I <char> IMEI protection options:\n" + " d <file> = Retrieve die id from target and write to <file>.\n" + " n <num> = 16 digits representing the IMEI-SV, [8 TAC]+[6 SNR]+\n" + " [2 SVN], which is used for non-secure E-samples or\n" + " secure E-samples when the die id is not added to the\n" + " DIE_ID field of the manufacturer certificate.\n" + " a <addr> = Address of the platform certificate stored in flash.\n" + " -R Request firmware certificate.\n" + " -D <num> Insert a delay before detection of flash type. This delay is used\n" + " for changing the memory mapping on CS5 due to a bug in ROM code\n" + " 0x0410 (see SECURITY.txt) or for connecting to target via JTAG.\n" + " -U <num> UART baudrate during flash programmer download. Default is 115200.\n" + " -u <num> UART timeout configuration. Default is 0.\n" + " -B <num> Block size. Must be a modulus of 64 bytes. Default is %d bytes.\n", arg_block_size + // End Secure Calypso Plus + ); +} + +static void main_args(int argc, char *argv[]) +{ + char ch; + int i; + // IMEI Protection + char d_i, d_digit; + char a_imeisv_format[] = "The IMEI-SV must consist of 16 digits in compliance with the following format:\n[8 TAC]+[6 SNR]+[2 SVN]\n"; + + if (argc == 1) { + fluid_welcome(); + main_help(); + exit(0); + } + + for (i = argc - 1; i >= 0; i--) { + // TODO?: scan for filenames. + } + + while ((ch = getopt(argc, argv, + "f:p:b:cCzZjJt:e:s:r:w:nlqg:o:vkd:i:hVyI:RD:U:u:B:")) != -1) + { + switch (ch) + { + case 'f': + if (arg_file_list_size < ARG_FILE_LIST_SIZE_MAX - 1) + arg_file_list[arg_file_list_size++] = optarg; + arg_file_list[arg_file_list_size] = NULL; + break; + case 'p': + arg_uart_port = arg_long_get(); + if (arg_uart_port < 1 || 24 < arg_uart_port) + main_error(E_BADARG); + break; + case 'b': + arg_uart_baudrate = arg_long_get(); + arg_uart_baudrate = serial_is_baudrate(arg_uart_baudrate); + if (arg_uart_baudrate == 0) + main_error(E_BADARG); + break; + case 't': + arg_target_type = *optarg; + break; + case 'c': arg_checksum = 1; break; + case 'C': arg_checksum = 0; break; + case 'z': arg_compress = 1; break; + case 'Z': arg_compress = 0; break; + case 'e': + if (*arg_erase_override != 0) + main_error(E_ARG_MULTI); + arg_erase_override = optarg; + break; + case 's': + while (*optarg) { + switch(*optarg++) { + case 'i': arg_image_map_show++; break; + case 's': arg_sector_map_show++; break; + case 'l': arg_sector_list_show++; break; + case 't': arg_timers_show++; break; + case 'T': arg_timers_extended_show++; break; + case 'c': arg_checksum_show++; break; + case 'x': arg_show_hexdump++; break; + } + } + break; + case 'r': + if (*arg_read != 0) + main_error(E_ARG_MULTI); + arg_read = optarg; + break; + case 'w': + if (*arg_write != 0) + main_error(E_ARG_MULTI); + arg_write = optarg; + break; + case 'l': arg_list_devices = 1; break; + case 'n': arg_dry_run++; break; + case 'k': arg_keep_going = 1; break; + case 'v': arg_verbose++; break; + case 'q': arg_verbose--; break; + case 'g': + if (*optarg != 'a' && + *optarg != 'c' && + *optarg != 'd' && + *optarg != 'x' && + *optarg != 'n') + main_error(E_BADARG); + arg_progress = *optarg; + break; + case 'o': + while (*optarg) { + tr(TrCmdLineParser, "main_args(): -o%s", optarg); + switch (*optarg) { + case 'e': arg_skip_erase = 1; break; + case 'R': arg_target_reset = 0; break; + case 'r': arg_target_reset = 2; break; + case 'o': arg_rom_bootloader = 1; break; + case 'O': arg_rom_bootloader = -1; break; + case 'l': arg_uart_level_convert = 1; break; + case 'b': + case 'm': arg_hexfile_type = *optarg; break; + case 'i': + optarg++; + arg_device_id0 = arg_long_get(); + if (*optarg == ',') { + optarg++; + arg_device_id1 = arg_long_get(); + } + else { + fprintf(stderr, "arg: '%s'", optarg); + main_error(E_BADARG); + } + optarg--; + break; + case 'd': + optarg++; + arg_boot_delay_rom = arg_long_get(); + if (*optarg == ',') { + optarg++; + arg_boot_delay_fluid = arg_long_get(); + } + else if (*optarg == 0) + arg_boot_delay_fluid = arg_boot_delay_rom; + else { + fprintf(stderr, "arg: '%s'", optarg); + main_error(E_BADARG); + } + optarg--; + break; + case '1': + case '2': + case '4': + arg_hexfile_memwidth = *optarg - '0'; + break; + default: + main_error(E_BADARG); + } + tr(TrCmdLineParser, "\n"); + optarg++; + } + break; + case 'd': + while (*optarg) { + switch (*optarg++) { + case 'h': main_debug_usage(); break; + case 'c': arg_debug_resume = 1; break; + case 'p': arg_debug_trace_pe = 1; break; + case 'r': arg_target_trace_enable = 1; break; + case 'o': arg_show_main_args = 1; break; + case 't': main_args_debug_trace(); break; + case 'v': fluid_compile_info(); exit(0); break; + case 'f': arg_tr_file = optarg; optarg += strlen(optarg); break; + case 'm': arg_tr_mask = arg_long_get(); break; + case 'i': arg_tr_spaces = arg_long_get(); break; + default: + main_error(E_BADARG); + } + } + optarg++; + break; + case 'i': main_example(*optarg); break; + case 'h': arg_usage = 1; break; + case 'V': fluid_welcome(); exit(0); + case 'y': arg_errorfd = 1; break; + // IMEI Protection + case 'I': + switch (*optarg++) { + case 'd': + if (*arg_die_id_file_name != 0) + main_error(E_ARG_MULTI); + if (*optarg == 0) + optarg++; + arg_die_id_file_name = optarg; + break; + case 'n': + if (*arg_imeisv != 0) + main_error(E_ARG_MULTI); + if (*optarg == 0) + optarg++; + arg_imeisv = optarg; + if (strlen(arg_imeisv) != C_IMEISV_DIGITS) { + fprintf(stderr, a_imeisv_format); + main_error(E_BADARG); + } + for (d_i = 0; d_i < C_IMEISV_DIGITS; d_i++) { + sscanf(arg_imeisv++, "%1c", &d_digit); + if (d_digit < '0' ||d_digit > '9') { + fprintf(stderr, a_imeisv_format); + main_error(E_BADARG); + } + } + arg_imeisv = optarg; // Re-assign arg_imeisv after error check + break; + case 'a': + if (*arg_platform_certificate_addr != 0) + main_error(E_ARG_MULTI); + if (*optarg == 0) + optarg++; + arg_platform_certificate_addr = optarg; + if ((strlen(arg_platform_certificate_addr) == C_PLATFORM_CERT_ADDR_DIGITS + 2) && + (arg_platform_certificate_addr[0] == '0') && + (arg_platform_certificate_addr[1] == 'x')) + arg_platform_certificate_addr += 2; + else if (strlen(arg_platform_certificate_addr) != C_PLATFORM_CERT_ADDR_DIGITS) { + fprintf(stderr, "The platform certificate address must comply with the following format, e.g.,\n0x04650000\n"); + main_error(E_BADARG); + } + break; + default: + main_error(E_BADARG); + } + break; + // Secure Calypso Plus + case 'R': + arg_request_certificate = 1; + d_ram_loader.b_certificate_request = C_TRUE; + break; + case 'D': + arg_delay_for_changing_cs5 = arg_long_get(); + if (arg_delay_for_changing_cs5 < 0) + main_error(E_BADARG); + break; + case 'U': + arg_uart_baudrate_during_cmd_download = arg_long_get(); + if (arg_uart_baudrate_during_cmd_download < 0) + main_error(E_BADARG); + break; + case 'u': + arg_uart_timeout_configuration = arg_long_get(); + d_ram_loader.d_uart_timeout = (UWORD32) arg_uart_timeout_configuration; + if (d_ram_loader.d_uart_timeout < 0) + main_error(E_BADARG); + break; + case 'B': + arg_block_size = arg_long_get(); + d_ram_loader.d_nb_byte_in_block = (UWORD32) arg_block_size; + if (d_ram_loader.d_nb_byte_in_block < 1) + main_error(E_BADARG); + break; + // End Secure Calypso Plus + default: + main_usage(); + exit(-E_BADARG); + } + } + + if (arg_usage) { + main_usage(); + exit(0); + } + + if (arg_show_main_args) { + printf("Command line option values:\n"); + printf("argv[0] = '%s'\n", argv[0]); + printf("\n"); + printf("port = %d\n", arg_uart_port); + printf("baudrate = %d\n", arg_uart_baudrate); + + printf("target_trace_enable = %d\n", arg_target_trace_enable); + printf("\n"); + } + +} + +static long arg_long_get(void) +{ + long value; + char *endp; + + errno = 0; + value = strtol(optarg, &endp, 0); + + if (errno == ERANGE || endp == optarg) { + fprintf(stderr, "Invalid command line number argument: '%s'", optarg); + exit(1); + } + optarg = endp; + return value; +} + + +/****************************************************************************** + * Globals and Main + ******************************************************************************/ + +int flowf(int level, char *format, ...) +{ + int n = 0; + va_list args; + char buf[1024]; + + if (level <= arg_verbose) { + va_start(args, format); + vsprintf(buf, format, args); + + n = fprintf(stdout, "%s", buf); + } + fflush(stdout); + + return n; +} + +int main(int argc, char *argv[]) +{ + int error; + + file_read_rc(".fluidrc"); + + main_args(argc, argv); + argv_0 = argv[0]; + + if (arg_verbose >= NORMAL) + fluid_welcome(); + + // Init tracing library + tr_init(arg_tr_spaces, arg_tr_file); + tr_mask(TrMAIN | arg_tr_mask); + + error = fluid_machine(); + + if (error < 0) + main_error(error); + + exit(-error); +}