/* ** Copyright (C) 2002-2004 Daniel Caujolle-Bert ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** */ /* required for getsubopt() */ #ifndef __sun #define _XOPEN_SOURCE 500 #endif #define _BSD_SOURCE 1 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #ifdef HAVE_GETOPT_LONG # include #else # include "getopt.h" #endif #include "common.h" #include "commands.c" #define SORT_VERSION "0.0.1" /* options args */ static const char *short_options = "?ho:v"; static struct option long_options[] = { { "help" , no_argument , 0, 'h' }, { "output" , required_argument, 0, 'o' }, { "version" , no_argument , 0, 'v' }, { 0 , no_argument , 0, 0 } }; typedef struct { FILE *fd; char buf[256]; char *ln; int lines; char **symlines; } symfile_t; static symfile_t symfile; static char *lookup_symfile(int value); static int cmd_max_len = 0; #define MAX_COLS 98 /* * Sorting function, it comes from GNU fileutils package. */ #define S_N 0x0 #define S_I 0x4 #define S_F 0x8 #define S_Z 0xC #define CMP 2 #define LEN 3 #define _ISDIGIT(c) ((unsigned) (c) - '0' <= 9) static int sort_cmds(const char *s1, const char *s2) { const unsigned char *p1 = (const unsigned char *) s1; const unsigned char *p2 = (const unsigned char *) s2; unsigned char c1, c2; int state; int diff; static const unsigned int next_state[] = { S_N, S_I, S_Z, S_N, S_N, S_I, S_I, S_I, S_N, S_F, S_F, S_F, S_N, S_F, S_Z, S_Z }; static const int result_type[] = { CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, -1, -1, CMP, 1, LEN, LEN, CMP, 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, 1, 1, CMP, -1, CMP, CMP, CMP, -1, CMP, CMP, CMP }; if(p1 == p2) return 0; c1 = *p1++; c2 = *p2++; state = S_N | ((c1 == '0') + (_ISDIGIT(c1) != 0)); while((diff = c1 - c2) == 0 && c1 != '\0') { state = next_state[state]; c1 = *p1++; c2 = *p2++; state |= (c1 == '0') + (_ISDIGIT(c1) != 0); } state = result_type[state << 2 | ((c2 == '0') + (_ISDIGIT(c2) != 0))]; switch(state) { case CMP: return diff; case LEN: while(_ISDIGIT(*p1++)) if(!_ISDIGIT(*p2++)) return 1; return _ISDIGIT(*p2) ? -1 : diff; default: return state; } } static int sort_commands(const commands_t *cmd1, const commands_t *cmd2) { return(sort_cmds(cmd1->command, cmd2->command)); } static void output_helpsyntax(FILE *stream, const char *helpsyntax, int xine_header, int *llen) { char *p = (char *)helpsyntax; while(*p != '\0') { switch(*p) { case '\n': fprintf(stream, "\\n\""); *llen += 3; if(xine_header) { int i = MAX_COLS; i -= (*llen + 1); while(i > 0) { fprintf(stream, " "); i--; } fprintf(stream, "\\"); } fprintf(stream, "\n"); fprintf(stream, " \""); *llen = 5; break; default: fprintf(stream, "%c", *p); *llen += 1; break; } p++; } } static void output_cmd(FILE *stream, commands_t *cmd) { static char *argstypes[] = { "GASP", "NO_ARGS", "REQUIRE_ARGS", "OPTIONAL_ARGS", NULL }; int llen = 0, xine_header = 0; if(cmd->command) fprintf(stream, " { \"%s\",", cmd->command); else fprintf(stream, " { NULL,"); llen = 5 + ((cmd->command) ? (strlen(cmd->command) + 2) : 4) + 1; { int i = cmd_max_len + 1; if(cmd->command) i -= strlen(cmd->command); else i -= 2; llen += i; while(i > 0) { fprintf(stream, " "); i--; } } fprintf(stream, "%s,", (cmd->argtype > 0) ? argstypes[cmd->argtype] : "-1"); llen += strlen((cmd->argtype > 0) ? argstypes[cmd->argtype] : "-1") + 1; { int i = 14; i -= strlen((cmd->argtype > 0) ? argstypes[cmd->argtype] : "-1"); llen += i; while(i > 0) { fprintf(stream, " "); i--; } } fprintf(stream, "%s,", (cmd->function) ? lookup_symfile((int)cmd->function) : "NULL"); llen += strlen((cmd->function) ? lookup_symfile((int)cmd->function) : "NULL") + 1; if(cmd->function) { char *fname = lookup_symfile((int)cmd->function); if((!strncmp(fname, "_xine_", 6)) || (!strncmp(fname, "_NAPI_", 6))) { int i = MAX_COLS; xine_header = 1; i -= llen; while(i > 0) { fprintf(stream, " "); i--; } fprintf(stream, "\\"); } } fprintf(stream, "%c", '\n'); llen = 0; if(cmd->help) { fprintf(stream, " \""); llen += 5; output_helpsyntax(stream, cmd->help, xine_header, &llen); fprintf(stream, "\","); llen += 2; } else { fprintf(stream, " %s,", "NULL"); llen += 8; } if(xine_header) { int i = MAX_COLS; i -= (llen + 1); while(i > 0) { fprintf(stream, " "); i--; } fprintf(stream, "\\"); } fprintf(stream, "\n"); llen = 0; if(cmd->syntax) { fprintf(stream, " \""); llen += 5; output_helpsyntax(stream, cmd->syntax, xine_header, &llen); fprintf(stream, "\""); llen++; if(xine_header) { int i = MAX_COLS; i -= (llen + 1); while(i > 0) { fprintf(stream, " "); i--; } fprintf(stream, "\\"); } } else { fprintf(stream, " NULL"); llen += 8; if(xine_header) { int i = MAX_COLS; i -= (llen + 1); while(i > 0) { fprintf(stream, " "); i--; } fprintf(stream, "\\"); } } fprintf(stream, "\n"); llen = 0; fprintf(stream, " }%c", (cmd->command) ? ',': ' '); llen += 4; if(xine_header) { int i = MAX_COLS; i -= (llen + 1); while(i > 0) { fprintf(stream, " "); i--; } fprintf(stream, "\\"); } fprintf(stream, "\n"); } static char *lookup_symfile(int value) { int i = 0; int addr; char p; static char symname[2048]; while(symfile.symlines[i] != NULL) { memset(&symname, 0, sizeof(symname)); if(sscanf(symfile.symlines[i], "%x %c %s", &addr, &p, &symname[0]) == 3) { if(addr == value) return symname; } i++; } return NULL; } static int open_symfile(char *filename) { if((symfile.fd = fopen(filename, "r")) != NULL) { symfile.symlines = (char **) malloc(sizeof(char *)); symfile.lines = 0; while((symfile.ln = fgets(symfile.buf, 255, symfile.fd)) != NULL) { symfile.symlines = (char **) realloc(symfile.symlines, sizeof(char *) * (symfile.lines + 2)); symfile.buf[strlen(symfile.buf) - 1] = '\0'; symfile.symlines[symfile.lines] = strdup(symfile.ln); symfile.lines++; } symfile.symlines[symfile.lines] = NULL; return 1; } fprintf(stderr, "Unable to open '%s': %s\n", filename, strerror(errno)); return 0; } static void close_symfile(void) { int i = 0; fclose(symfile.fd); for(i = 0; i < symfile.lines; i++) toxine_free(symfile.symlines[i]); toxine_free(symfile.symlines); } static void print_version(void) { printf("sortcmds - toxine's commands sort utility v%s\n" "(c) 2002 by Daniel Caujolle-Bert .\n", SORT_VERSION); } /* * Display full help. */ static void print_usage(void) { printf("Usage: sortcmds [options]\n"); printf(" -o, --output Save commands_t struct to .\n"); printf(" -v, --version Display version.\n"); printf(" -h, --help Display this help text.\n"); printf("\n"); } int main(int argc, char **argv) { int i = 0; int clen = (sizeof(commands) / sizeof(commands[0])) - 1; FILE *output = stdout; char *ofile = NULL; int c = '?'; int option_index = 0; int (*func)() = sort_commands; commands_t *cc; int result, cmdlen, use_output = 0; opterr = 0; while((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != EOF) { switch(c) { case 'o': ofile = optarg; if((output = fopen(ofile, "w")) == NULL) { fprintf(stderr, "Cannot open %s: %s\n", ofile, strerror(errno)); exit(1); } use_output = 1; break; case 'v': print_version(); exit(1); break; case 'h': case '?': print_usage(); exit(1); break; default: print_usage(); fprintf(stderr, "invalid argument %d => exit\n",c); exit(1); } } if(use_output) { print_version(); fprintf(stdout, " Creating '%s' file...", ofile); fflush(stdout); } cc = (commands_t *) malloc(sizeof(commands_t) * (clen + 1)); while(commands[i].command != NULL) { cc[i].command = strdup(commands[i].command); if((cmdlen = strlen(commands[i].command)) > cmd_max_len) cmd_max_len = cmdlen; cc[i].argtype = commands[i].argtype; cc[i].function = commands[i].function; cc[i].help = commands[i].help ? strdup(commands[i].help) : NULL; cc[i].syntax = commands[i].syntax ? strdup(commands[i].syntax) : NULL; i++; } cc[i].command = NULL; cc[i].argtype = -1; cc[i].function = NULL; cc[i].help = NULL; cc[i].syntax = NULL; qsort(cc, clen, sizeof(commands_t), func); if((result = toxine_system(0, "nm ./sortcmds > ./symfile.tox")) >= 0) { if(open_symfile("./symfile.tox")) { fprintf(output, "static commands_t commands[] = {\n"); for(i = 0; i <= clen; i++) output_cmd(output, &cc[i]); (void) toxine_system(0, "rm -f ./symfile.tox"); close_symfile(); fprintf(output, "};\n"); } } for(i = 0; i <= clen; i++) { toxine_free(cc[i].command); toxine_free(cc[i].help); toxine_free(cc[i].syntax); } toxine_free(cc); if(use_output) { fclose(output); fprintf(stdout, "\b\b\b: done.\n"); fflush(stdout); } return 1; }