static int check_second_line(struct reader_t *rsol, struct reader_t *rout) { if (rsol->c == EOF) return ANSW_OK; /* skip_blank_lines(rout) will be called later */ reader_read(rsol); reader_read(rout); for (;;) { reader_skipblank(rsol); reader_skipblank(rout); if ((rsol->c == EOF) || isnewline(rsol->c)) return ANSW_OK; /* skip_blank_lines(rout) will be called later */ if (rsol->c != rout->c) return ANSW_FAIL; read_digit_while_eq(rsol, rout); if ((rsol->c == EOF) || isnewline(rsol->c)) return ANSW_OK; /* skip_blank_lines(rout) will be called later */ if ((rsol->c == rout->c) || (isblank(rsol->c) && isblank(rout->c))) continue; return ANSW_FAIL; } }
static void read_digit_while_eq(struct reader_t *rsol, struct reader_t *rout) { while ((rsol->c != EOF) && isdigit(rsol->c) && (rsol->c == rout->c)) { reader_read(rsol); reader_read(rout); } }
int main(int argc, char **argv) { init_runtime(); //env_dump(globals); //symtab_dump(); printf("\nREADER TEST:\n"); value_prn(reader_read(" 135 ")); value_prn(reader_read(" -35 ")); value_prn(reader_read(" foo'bah ")); value_prn(reader_read(" [1 23 4]")); value_prn(reader_read(" [1 23 4 55 six 7 eight]")); value_prn(reader_read(" 'barf ")); value_prn(reader_read(" [1 23 [4 55 'six 7] \"eight\" 9]")); value_prn(reader_read(" {foo=bar baz=\"barf\" zoo=1221}")); /* Output expected: READER TEST: 135 -35 foo'bah [1 23 4] [1 23 4 55 six 7 eight] [quote barf] [1 23 [4 55 [quote six] 7] eight 9] {foo=bar baz=barf zoo=1221} */ return 0; }
static void fill_buffer(struct mad_local_data *data, long offset) { size_t bytes_read; if (data->seekable && offset >= 0) { reader_seek(data->mad_fd, data->offset + offset, SEEK_SET); bytes_read = reader_read(data->mad_map, MAD_BUFSIZE, data->mad_fd); data->bytes_avail = bytes_read; data->map_offset = offset; } else { memmove(data->mad_map, data->mad_map + MAD_BUFSIZE - data->bytes_avail, data->bytes_avail); bytes_read = reader_read(data->mad_map + data->bytes_avail, MAD_BUFSIZE - data->bytes_avail, data->mad_fd); data->map_offset += (MAD_BUFSIZE - data->bytes_avail); data->bytes_avail += bytes_read; } }
/// Implementation of the builtin breakpoint command, used to launch the interactive debugger. static int builtin_breakpoint(parser_t &parser, io_streams_t &streams, wchar_t **argv) { wchar_t *cmd = argv[0]; if (argv[1] != NULL) { streams.err.append_format(BUILTIN_ERR_ARG_COUNT1, cmd, 0, builtin_count_args(argv) - 1); return STATUS_INVALID_ARGS; } // If we're not interactive then we can't enter the debugger. So treat this command as a no-op. if (!shell_is_interactive()) { return STATUS_CMD_ERROR; } // Ensure we don't allow creating a breakpoint at an interactive prompt. There may be a simpler // or clearer way to do this but this works. const block_t *block1 = parser.block_at_index(1); if (!block1 || block1->type() == BREAKPOINT) { streams.err.append_format(_(L"%ls: Command not valid at an interactive prompt\n"), cmd); return STATUS_ILLEGAL_CMD; } const breakpoint_block_t *bpb = parser.push_block<breakpoint_block_t>(); reader_read(STDIN_FILENO, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(bpb); return proc_get_last_status(); }
int log_read(struct log *log, int hpos, char *buffer, unsigned int buffer_sz, struct keyvalue *kv) { struct hashdir_item hi = hashdir_get(log->hashdir, hpos); assert(hi.size <= buffer_sz); return reader_read(log->reader, hi.offset, buffer, hi.size, kv); }
static int check_first_line(struct reader_t *rsol, struct reader_t *rout) { reader_read(rsol); reader_read(rout); reader_skipblank(rsol); reader_skipblank(rout); read_digit_while_eq(rsol, rout); if (rsol->c == rout->c) return ANSW_OK; if ((rsol->c != EOF) && isdigit(rsol->c)) return ANSW_FAIL; reader_skipblank(rout); if ((rout->c == EOF) || isnewline(rout->c)) return ANSW_OK; return ANSW_FAIL; }
void dump(void) { int size, count=0, last_was_overflow=FALSE, last_was_none=FALSE; Record *rec; while (1) { switch (size = reader_read(reader, buf)) { case 0: if (FALSE == last_was_none) { db_truncate(MAX_TRACES); last_was_none = TRUE; } if (should_stop) { db_commit(); should_stop = 0; return; } db_commit(); usleep(50000); // 50 ms count = 0; break; case READ_OVERFLOW: if (FALSE == last_was_overflow) { db_handle_lost(); last_was_overflow = TRUE; } break; default: count++; last_was_overflow = FALSE; last_was_none = FALSE; rec = record__unpack(NULL, size, buf); assert(NULL != rec); db_handle_record(rec); record__free_unpacked(rec, NULL); if (COMMIT_INTERVAL < count) { count = 0; db_truncate(MAX_TRACES); db_commit(); } } } }
int log_iterate_sorted(struct log *log, uint64_t prefetch_size, log_iterate_callback callback, void *userdata) { struct timeval tv0, tv1; gettimeofday(&tv0, NULL); struct hashdir *shd = hashdir_dup_sorted(log->hashdir); gettimeofday(&tv1, NULL); log_info(log->db, "Sorting index in log %llx took %5li ms.", (unsigned long long)log->log_number, TIMEVAL_MSEC_SUBTRACT(tv1, tv0)); int hpos_max = hashdir_size(shd); int last_hpos = 1; int r = 0; int i; for (i=1; i < hpos_max; i++) { if (i == last_hpos) { last_hpos = _iterate_prefetch(log, shd, last_hpos, prefetch_size); } struct hashdir_item hi = hashdir_get(shd, i); struct keyvalue kv; char *buf = malloc(hi.size); r = reader_read(log->reader, hi.offset, buf, hi.size, &kv); if (r) { free(buf); break; } r = callback(userdata, kv.key, kv.key_sz, kv.value, kv.value_sz); free(buf); if (r) { break; } } hashdir_free(shd); return r; }
void test_ring() { int size; unsigned char *buf = malloc(sizeof(unsigned char) * BUF_SIZE); Ring *ring = ring_malloc(BUF_SIZE); RingReader *reader = reader_malloc(ring); size = reader_read(reader, buf); assert(0 == size); printf("one write and one read\n"); ring_write(ring, "11", 2); size = reader_read(reader, buf); assert(2 == size); assert(0 == memcmp(buf, "11", 2)); printf("two writes and one read due to overflow\n"); ring_write(ring, "22", 2); ring_write(ring, "33", 2); size = reader_read(reader, buf); assert(-1 == size); size = reader_read(reader, buf); assert(2 == size); assert(0 == memcmp(buf, "33", 2)); printf("two small writes and two reads\n"); ring_write(ring, "4", 1); ring_write(ring, "5", 1); size = reader_read(reader, buf); assert(1 == size); assert(0 == memcmp(buf, "4", 1)); size = reader_read(reader, buf); assert(1 == size); assert(0 == memcmp(buf, "5", 1)); printf("fill once again\n"); ring_write(ring, "123456", 6); size = reader_read(reader, buf); assert(6 == size); assert(0 == memcmp(buf, "123456", 6)); ring_free(ring); }
int main( int argc, char **argv ) { struct stat tmp; int res=1; const char *cmd=0; int my_optind=0; set_main_thread(); setup_fork_guards(); wsetlocale( LC_ALL, L"" ); is_interactive_session=1; program_name=L"fish"; stat("----------FISH_HIT_MAIN----------", &tmp); my_optind = fish_parse_opt( argc, argv, &cmd ); /* No-exec is prohibited when in interactive mode */ if( is_interactive_session && no_exec) { debug( 1, _(L"Can not use the no-execute mode when running an interactive session") ); no_exec = 0; } const struct config_paths_t paths = determine_config_directory_paths(argv[0]); proc_init(); event_init(); wutil_init(); //parser_init(); builtin_init(); function_init(); env_init(&paths); reader_init(); history_init(); parser_t &parser = parser_t::principal_parser(); if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); if( read_init(paths) ) { if( cmd != 0 ) { wchar_t *cmd_wcs = str2wcs( cmd ); res = parser.eval( cmd_wcs, 0, TOP ); free(cmd_wcs); reader_exit(0, 0); } else { if( my_optind == argc ) { res = reader_read( STDIN_FILENO, 0 ); } else { char **ptr; char *file = *(argv+(my_optind++)); int i; int fd; wchar_t *rel_filename, *abs_filename; if( ( fd = open(file, O_RDONLY) ) == -1 ) { wperror( L"open" ); return 1; } // OK to not do this atomically since we cannot have gone multithreaded yet set_cloexec(fd); if( *(argv+my_optind)) { wcstring sb; for( i=1,ptr = argv+my_optind; *ptr; i++, ptr++ ) { if( i != 1 ) sb.append( ARRAY_SEP_STR ); sb.append( str2wcstring( *ptr )); } env_set( L"argv", sb.c_str(), 0 ); } rel_filename = str2wcs( file ); abs_filename = wrealpath( rel_filename, 0 ); if( !abs_filename ) { abs_filename = wcsdup(rel_filename); } reader_push_current_filename( intern( abs_filename ) ); free( rel_filename ); free( abs_filename ); res = reader_read( fd, 0 ); if( res ) { debug( 1, _(L"Error while reading file %ls\n"), reader_current_filename()?reader_current_filename(): _(L"Standard input") ); } reader_pop_current_filename(); } } } proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res ); history_destroy(); proc_destroy(); builtin_destroy(); reader_destroy(); parser.destroy(); wutil_destroy(); event_destroy(); env_destroy(); if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); return res?STATUS_UNKNOWN_COMMAND:proc_get_last_status(); }
int main(int argc, char **argv) { int res = 1; int my_optind = 0; program_name = L"fish"; set_main_thread(); setup_fork_guards(); signal_unblock_all(); setlocale(LC_ALL, ""); fish_setlocale(); // struct stat tmp; // stat("----------FISH_HIT_MAIN----------", &tmp); if (!argv[0]) { static const char *dummy_argv[2] = {"fish", NULL}; argv = (char **)dummy_argv; //!OCLINT(parameter reassignment) argc = 1; //!OCLINT(parameter reassignment) } fish_cmd_opts_t opts; my_optind = fish_parse_opt(argc, argv, &opts); // No-exec is prohibited when in interactive mode. if (is_interactive_session && no_exec) { debug(1, _(L"Can not use the no-execute mode when running an interactive session")); no_exec = 0; } // Only save (and therefore restore) the fg process group if we are interactive. See issues // #197 and #1002. if (is_interactive_session) { save_term_foreground_process_group(); } const struct config_paths_t paths = determine_config_directory_paths(argv[0]); env_init(&paths); // Set features early in case other initialization depends on them. // Start with the ones set in the environment, then those set on the command line (so the // command line takes precedence). if (auto features_var = env_get(L"fish_features")) { for (const wcstring &s : features_var->as_list()) { mutable_fish_features().set_from_string(s); } } mutable_fish_features().set_from_string(opts.features); proc_init(); builtin_init(); misc_init(); reader_init(); parser_t &parser = parser_t::principal_parser(); const io_chain_t empty_ios; if (read_init(paths)) { // Stomp the exit status of any initialization commands (issue #635). proc_set_last_status(STATUS_CMD_OK); // Run post-config commands specified as arguments, if any. if (!opts.postconfig_cmds.empty()) { res = run_command_list(&opts.postconfig_cmds, empty_ios); } if (!opts.batch_cmds.empty()) { // Run the commands specified as arguments, if any. if (is_login) { // Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. fish_xdm_login_hack_hack_hack_hack(&opts.batch_cmds, argc - my_optind, argv + my_optind); } res = run_command_list(&opts.batch_cmds, empty_ios); reader_exit(0, 0); } else if (my_optind == argc) { // Implicitly interactive mode. res = reader_read(STDIN_FILENO, empty_ios); } else { char *file = *(argv + (my_optind++)); int fd = open(file, O_RDONLY); if (fd == -1) { perror(file); } else { // OK to not do this atomically since we cannot have gone multithreaded yet. set_cloexec(fd); wcstring_list_t list; for (char **ptr = argv + my_optind; *ptr; ptr++) { list.push_back(str2wcstring(*ptr)); } env_set(L"argv", ENV_DEFAULT, list); const wcstring rel_filename = str2wcstring(file); reader_push_current_filename(rel_filename.c_str()); res = reader_read(fd, empty_ios); if (res) { debug(1, _(L"Error while reading file %ls\n"), reader_current_filename() ? reader_current_filename() : _(L"Standard input")); } reader_pop_current_filename(); } } } int exit_status = res ? STATUS_CMD_UNKNOWN : proc_get_last_status(); // TODO: The generic process-exit event is useless and unused. // Remove this in future. proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), exit_status); event_fire_generic(L"fish_exit"); restore_term_mode(); restore_term_foreground_process_group(); if (g_profiling_active) { parser.emit_profiling(s_profiling_output_filename); } history_save_all(); proc_destroy(); exit_without_destructors(exit_status); return EXIT_FAILURE; // above line should always exit }
int main(int argc, char **argv) { int res=1; int my_optind=0; set_main_thread(); setup_fork_guards(); wsetlocale(LC_ALL, L""); is_interactive_session=1; program_name=L"fish"; //struct stat tmp; //stat("----------FISH_HIT_MAIN----------", &tmp); std::vector<std::string> cmds; my_optind = fish_parse_opt(argc, argv, &cmds); /* No-exec is prohibited when in interactive mode */ if (is_interactive_session && no_exec) { debug(1, _(L"Can not use the no-execute mode when running an interactive session")); no_exec = 0; } /* Only save (and therefore restore) the fg process group if we are interactive. See #197, #1002 */ if (is_interactive_session) { save_term_foreground_process_group(); } const struct config_paths_t paths = determine_config_directory_paths(argv[0]); proc_init(); event_init(); wutil_init(); builtin_init(); function_init(); env_init(&paths); reader_init(); history_init(); /* For setcolor to support term256 in config.fish (#1022) */ update_fish_term256(); parser_t &parser = parser_t::principal_parser(); if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); const io_chain_t empty_ios; if (read_init(paths)) { /* Stop the exit status of any initialization commands (#635) */ proc_set_last_status(STATUS_BUILTIN_OK); /* Run the commands specified as arguments, if any */ if (! cmds.empty()) { /* Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. */ if (is_login) { fish_xdm_login_hack_hack_hack_hack(&cmds, argc - my_optind, argv + my_optind); } for (size_t i=0; i < cmds.size(); i++) { const wcstring cmd_wcs = str2wcstring(cmds.at(i)); res = parser.eval(cmd_wcs, empty_ios, TOP); } reader_exit(0, 0); } else { if (my_optind == argc) { res = reader_read(STDIN_FILENO, empty_ios); } else { char **ptr; char *file = *(argv+(my_optind++)); int i; int fd; if ((fd = open(file, O_RDONLY)) == -1) { wperror(L"open"); return 1; } // OK to not do this atomically since we cannot have gone multithreaded yet set_cloexec(fd); if (*(argv+my_optind)) { wcstring sb; for (i=1,ptr = argv+my_optind; *ptr; i++, ptr++) { if (i != 1) sb.append(ARRAY_SEP_STR); sb.append(str2wcstring(*ptr)); } env_set(L"argv", sb.c_str(), 0); } const wcstring rel_filename = str2wcstring(file); const wchar_t *abs_filename = wrealpath(rel_filename, NULL); if (!abs_filename) { abs_filename = wcsdup(rel_filename.c_str()); } reader_push_current_filename(intern(abs_filename)); free((void *)abs_filename); res = reader_read(fd, empty_ios); if (res) { debug(1, _(L"Error while reading file %ls\n"), reader_current_filename()?reader_current_filename(): _(L"Standard input")); } reader_pop_current_filename(); } } } proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), res); restore_term_mode(); restore_term_foreground_process_group(); history_destroy(); proc_destroy(); builtin_destroy(); reader_destroy(); parser.destroy(); wutil_destroy(); event_destroy(); env_destroy(); if (g_log_forks) printf("%d: g_fork_count: %d\n", __LINE__, g_fork_count); exit_without_destructors(res ? STATUS_UNKNOWN_COMMAND : proc_get_last_status()); return EXIT_FAILURE; //above line should always exit }
/// The source builtin, sometimes called `.`. Evaluates the contents of a file in the current /// context. int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { ASSERT_IS_MAIN_THREAD(); const wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); help_only_cmd_opts_t opts; int optind; int retval = parse_help_only_cmd_opts(opts, &optind, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { builtin_print_help(parser, streams, cmd, streams.out); return STATUS_CMD_OK; } int fd; struct stat buf; const wchar_t *fn, *fn_intern; if (argc == optind || wcscmp(argv[optind], L"-") == 0) { // Either a bare `source` which means to implicitly read from stdin or an explicit `-`. if (argc == optind && !streams.stdin_is_directly_redirected) { // Don't implicitly read from the terminal. return STATUS_CMD_ERROR; } fn = L"-"; fn_intern = fn; fd = dup(streams.stdin_fd); } else { if ((fd = wopen_cloexec(argv[optind], O_RDONLY)) == -1) { streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), cmd, argv[optind]); builtin_wperror(cmd, streams); return STATUS_CMD_ERROR; } if (fstat(fd, &buf) == -1) { close(fd); streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), cmd, argv[optind]); builtin_wperror(L"source", streams); return STATUS_CMD_ERROR; } if (!S_ISREG(buf.st_mode)) { close(fd); streams.err.append_format(_(L"%ls: '%ls' is not a file\n"), cmd, argv[optind]); return STATUS_CMD_ERROR; } fn_intern = intern(argv[optind]); } const source_block_t *sb = parser.push_block<source_block_t>(fn_intern); reader_push_current_filename(fn_intern); // This is slightly subtle. If this is a bare `source` with no args then `argv + optind` already // points to the end of argv. Otherwise we want to skip the file name to get to the args if any. env_set_argv(argv + optind + (argc == optind ? 0 : 1)); retval = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(sb); if (retval != STATUS_CMD_OK) { streams.err.append_format(_(L"%ls: Error while reading file '%ls'\n"), cmd, fn_intern == intern_static(L"-") ? L"<stdin>" : fn_intern); } else { retval = proc_get_last_status(); } // Do not close fd after calling reader_read. reader_read automatically closes it before calling // eval. reader_pop_current_filename(); return retval; }
int main(int argc, char **argv) { int res = 1; int my_optind = 0; program_name = L"fish"; set_main_thread(); setup_fork_guards(); setlocale(LC_ALL, ""); fish_setlocale(); // struct stat tmp; // stat("----------FISH_HIT_MAIN----------", &tmp); if (!argv[0]) { static const char *dummy_argv[2] = {"fish", NULL}; argv = (char **)dummy_argv; //!OCLINT(parameter reassignment) argc = 1; //!OCLINT(parameter reassignment) } std::vector<std::string> cmds; my_optind = fish_parse_opt(argc, argv, &cmds); // No-exec is prohibited when in interactive mode. if (is_interactive_session && no_exec) { debug(1, _(L"Can not use the no-execute mode when running an interactive session")); no_exec = 0; } // Only save (and therefore restore) the fg process group if we are interactive. See issues // #197 and #1002. if (is_interactive_session) { save_term_foreground_process_group(); } const struct config_paths_t paths = determine_config_directory_paths(argv[0]); proc_init(); event_init(); builtin_init(); function_init(); env_init(&paths); reader_init(); history_init(); // For set_color to support term256 in config.fish (issue #1022). update_fish_color_support(); misc_init(); parser_t &parser = parser_t::principal_parser(); const io_chain_t empty_ios; if (read_init(paths)) { // Stomp the exit status of any initialization commands (issue #635). proc_set_last_status(STATUS_BUILTIN_OK); // Run the commands specified as arguments, if any. if (!cmds.empty()) { // Do something nasty to support OpenSUSE assuming we're bash. This may modify cmds. if (is_login) { fish_xdm_login_hack_hack_hack_hack(&cmds, argc - my_optind, argv + my_optind); } for (size_t i = 0; i < cmds.size(); i++) { const wcstring cmd_wcs = str2wcstring(cmds.at(i)); res = parser.eval(cmd_wcs, empty_ios, TOP); } reader_exit(0, 0); } else if (my_optind == argc) { // Interactive mode check_running_fishd(); res = reader_read(STDIN_FILENO, empty_ios); } else { char *file = *(argv + (my_optind++)); int fd = open(file, O_RDONLY); if (fd == -1) { perror(file); } else { // OK to not do this atomically since we cannot have gone multithreaded yet. set_cloexec(fd); if (*(argv + my_optind)) { wcstring sb; char **ptr; int i; for (i = 1, ptr = argv + my_optind; *ptr; i++, ptr++) { if (i != 1) sb.append(ARRAY_SEP_STR); sb.append(str2wcstring(*ptr)); } env_set(L"argv", sb.c_str(), 0); } const wcstring rel_filename = str2wcstring(file); reader_push_current_filename(rel_filename.c_str()); res = reader_read(fd, empty_ios); if (res) { debug(1, _(L"Error while reading file %ls\n"), reader_current_filename() ? reader_current_filename() : _(L"Standard input")); } reader_pop_current_filename(); } } } int exit_status = res ? STATUS_UNKNOWN_COMMAND : proc_get_last_status(); proc_fire_event(L"PROCESS_EXIT", EVENT_EXIT, getpid(), exit_status); restore_term_mode(); restore_term_foreground_process_group(); if (g_profiling_active) { parser.emit_profiling(s_profiling_output_filename); } history_destroy(); proc_destroy(); builtin_destroy(); reader_destroy(); event_destroy(); exit_without_destructors(exit_status); return EXIT_FAILURE; // above line should always exit }
/* Trying to fill info from id3 tagged file */ static void parse_id3 (const char *path, stream_info *info) { void *fd; unsigned char buf [2024]; unsigned char g; /* Open stream */ fd = reader_open (path, NULL, NULL); if (!fd) return; /* --------------------------------------------------- */ /* Trying to load id3v2 tags */ if (reader_read (buf, 10, fd) != 10) { reader_close (fd); return; } if (memcmp(buf, "ID3", 3) == 0) { /* Parse id3v2 tags */ /* Header */ unsigned char major_version = buf [3]; int f_unsynchronization = buf [5] & (1<<7); int f_extended_header = buf [5] & (1<<6); int f_experimental = buf [5] & (1<<5); int header_size = from_synchsafe4 (buf + 6); int name_size = buf [3] == 2 ? 3 : 4; int ext_size = 0; if (f_extended_header) { // alsaplayer_error ("FIXME: Extended header found in mp3." // "Please contact alsaplayer team.\n" // "Filename: %s", path); // reader_close (fd); // return; ext_size = 1; //stupid but should do } if (f_unsynchronization) { alsaplayer_error ("FIXME: f_unsynchronization is set." "Please contact alsaplayer team.\n" "Filename: %s", path); reader_close (fd); return; } if (f_experimental) { alsaplayer_error ("FIXME: f_experimental is set." "Please contact alsaplayer team.\n" "Filename: %s", path); reader_close (fd); return; } if (ext_size) { char b[4]; if (reader_read (b, 4, fd) != 4) { reader_close(fd); return; } if (major_version == 2) ext_size = from_synchsafe3 (b); else ext_size = from_synchsafe4 (b); if (reader_seek (fd, ext_size - 4, SEEK_CUR) < 0) { reader_close (fd); return; } } /* -- -- read frames -- -- */ while (reader_tell (fd) <= header_size + 10) { unsigned int size; /* Get name of this frame */ if (reader_read (buf, name_size, fd) != (unsigned)name_size) { reader_close (fd); return; } if (buf [0] == '\0') break; if (buf [0] < 'A') break; if (buf [0] > 'Z') break; /* Get size */ if (major_version == 2) { char sb [3]; if (reader_read (sb, 3, fd) != 3) { reader_close (fd); return; } size = from_synchsafe3 (sb); } else { char sb [4]; if (reader_read (sb, 4, fd) != 4) { reader_close (fd); return; } size = from_synchsafe4 (sb); } /* skip frame flags */ // if (reader_seek (fd, 1, SEEK_CUR) == -1) { // reader_close (fd); // return; // } int start = 0; // read them char b[2]; if (reader_read (b, 2, fd) != 2) { reader_close (fd); return; } else { if (b[1] & (1 << 6)) { // printf ("Grouping added\n"); start++; } if (b[1] & (1 << 3)) { // printf ("Compression added\n"); } if (b[1] & (1 << 2)) { // printf ("Encryption added\n"); } if (b[1] & (1 << 1)) { // printf ("Unsynch added\n"); } if (b[1] & (1 << 0)) { // printf ("Length added\n"); start+=4; } } if (size>=1024) { /* I will not support such long tags... * Only if someone ask for it... * not now... */ if (reader_seek (fd, size, SEEK_CUR) == -1) { reader_close (fd); return; } continue; } /* read info */ if (reader_read (buf + name_size, size, fd) != size) { reader_close (fd); return; } /* !!! Ok. There we have frame name and data. */ /* Lets use it. */ if (name_size == 4) { if (memcmp (buf, "TIT2", 4)==0) fill_from_id3v2 (info->title, buf + name_size + start, sizeof (info->title), size - start); else if (memcmp (buf, "TPE1", 4)==0) fill_from_id3v2 (info->artist, buf + name_size + start, sizeof (info->artist), size - start); else if (memcmp (buf, "TALB", 4)==0) fill_from_id3v2 (info->album, buf + name_size + start, sizeof (info->album), size - start); else if (memcmp (buf, "TYER", 4)==0) fill_from_id3v2 (info->year, buf + name_size + start, sizeof (info->year), size - start); else if (memcmp (buf, "COMM", 4)==0) fill_from_id3v2 (info->comment, buf + name_size + start, sizeof (info->comment), size - start); else if (memcmp (buf, "TRCK", 4)==0) fill_from_id3v2 (info->track, buf + name_size + start, sizeof (info->track), size - start); else if (memcmp (buf, "TCON", 4)==0) { /* Genre */ /* TODO: Optimize duplicated code */ unsigned int gindex; if (sscanf (buf + name_size + start +1, "(%u)", &gindex)==1) { if (gindex==255) *info->genre = '\0'; else if (sizeof (genres)/sizeof(char*) <= gindex) snprintf (info->genre, sizeof (info->genre), "(%u)", gindex); else snprintf (info->genre, sizeof (info->genre), "%s", genres[gindex]); } else fill_from_id3v2 (info->genre, buf + name_size + start, sizeof (info->genre), size - start); } } /* end of 'if name_size == 4' */ } /* end of frames read */ /* end parsing */ reader_close (fd); return; } /* end of id3v2 parsing */ /* --------------------------------------------------- */ /* Trying to load id3v1 tags */ if (reader_seek (fd, -128, SEEK_END) == -1) { reader_close (fd); return; } if (reader_read (buf, 128, fd) != 128) { reader_close (fd); return; } if (memcmp(buf, "TAG", 3) == 0) { /* ID3v1 frame found */ /* title */ strncpy (info->title, buf + 3, 30); rstrip (info->title); /* artist */ strncpy (info->artist, buf + 33, 30); rstrip (info->artist); /* album */ strncpy (info->album, buf + 63, 30); rstrip (info->album); /* year */ strncpy (info->year, buf + 93, 4); rstrip (info->year); /* comment */ strncpy (info->comment, buf + 97, 28); rstrip (info->comment); /* track number */ if (buf [125] == '\0') snprintf (info->track, sizeof (info->track), "%u", buf [126]); /* genre */ g = buf [127]; if (g==255) *info->genre = '\0'; else if (sizeof (genres)/sizeof(char*) <= g) snprintf (info->genre, sizeof (info->genre), "(%u)", g); else snprintf (info->genre, sizeof (info->genre), "%s", genres[g]); } /* end of id3v1 parsing */ reader_close (fd); }