1 /*============================================================================ 2 epub2txt v2 3 main.c 4 Copyright (c)2020-2024 Kevin Boone, GPL v3.0 5 ============================================================================*/ 6 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 #include 15 #include 16 #include "epub2txt.h" 17 #include "defs.h" 18 #include "log.h" 19 20 /*============================================================================ 21 sig_handler 22 ============================================================================*/ 23 static void sig_handler (int signo) 24 { 25 (void)signo; 26 epub2txt_cleanup(); 27 exit (0); 28 } 29 30 /*============================================================================ 31 main 32 ============================================================================*/ 33 int main (int argc, char **argv) 34 { 35 BOOL show_version = FALSE; 36 BOOL show_help = FALSE; 37 BOOL ascii = FALSE; 38 BOOL is_a_tty = FALSE; 39 BOOL noansi = FALSE; 40 BOOL raw = FALSE; 41 BOOL meta = FALSE; 42 BOOL notext = FALSE; 43 BOOL calibre = FALSE; 44 char *section_separator = NULL; 45 int width = 80; 46 47 static struct option long_options[] = 48 { 49 {"ascii", no_argument, NULL, 'a'}, 50 {"calibre", no_argument, NULL, 'c'}, 51 {"raw", no_argument, NULL, 'r'}, 52 {"meta", no_argument, NULL, 'm'}, 53 {"version", no_argument, NULL, 'v'}, 54 {"noansi", no_argument, NULL, 'n'}, 55 {"width", required_argument, NULL, 'w'}, 56 {"log", required_argument, NULL, 'l'}, 57 {"separator", required_argument, NULL, 's'}, 58 {"help", no_argument, NULL, 'h'}, 59 {"notext", no_argument, NULL, 0}, 60 {0, 0, 0, 0} 61 }; 62 63 64 log_set_level (WARNING); 65 66 // If we have a TTY, try to get the console width in columns. This 67 // may not work on all systems, so we need a fall-back. 68 if (isatty (STDOUT_FILENO)) 69 { 70 struct winsize ws; 71 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) 72 { 73 width = ws.ws_col; 74 } 75 is_a_tty = TRUE; 76 } 77 78 // If stdout is not a tty, try stdin. Why? Because if there _is_ a 79 // terminal attached somehow, we want to use its column width, 80 // if we use the "--wrap" option 81 if (!is_a_tty) 82 { 83 if (isatty (STDIN_FILENO)) 84 { 85 struct winsize ws; 86 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) 87 { 88 width = ws.ws_col; 89 } 90 } 91 is_a_tty = TRUE; 92 } 93 94 int opt; 95 while (1) 96 { 97 int option_index = 0; 98 opt = getopt_long (argc, argv, "avw:l:nrmchs:", 99 long_options, &option_index); 100 101 if (opt == -1) break; 102 103 switch (opt) 104 { 105 case 0: 106 if (strcmp (long_options[option_index].name, "version") == 0) 107 show_version = TRUE; 108 else if (strcmp (long_options[option_index].name, "width") == 0) 109 width = atoi (optarg); 110 else if (strcmp (long_options[option_index].name, "log") == 0) 111 log_set_level (atoi (optarg)); 112 else if (strcmp (long_options[option_index].name, "help") == 0) 113 show_help = TRUE; 114 else if (strcmp (long_options[option_index].name, "raw") == 0) 115 raw = TRUE; 116 else if (strcmp (long_options[option_index].name, "ascii") == 0) 117 ascii = TRUE; 118 else if (strcmp (long_options[option_index].name, "calibre") == 0) 119 calibre = TRUE; 120 else if (strcmp (long_options[option_index].name, "noansi") == 0) 121 noansi = TRUE; 122 else if (strcmp (long_options[option_index].name, "meta") == 0) 123 meta = TRUE; 124 else if (strcmp (long_options[option_index].name, "notext") == 0) 125 notext = TRUE; 126 else if (strcmp 127 (long_options[option_index].name, "separator") == 0) 128 section_separator = strdup (optarg); 129 else 130 exit (-1); 131 case 'a': 132 ascii = TRUE; break; 133 case 'c': 134 calibre = TRUE; break; 135 case 'n': 136 noansi = TRUE; break; 137 case 'h': 138 show_help = TRUE; break; 139 case 'v': 140 show_version = TRUE; break; 141 case 'r': 142 raw = TRUE; break; 143 case 'l': 144 log_set_level (atoi(optarg)); break; 145 case 'm': 146 meta = TRUE; break; 147 case 'w': 148 width = atoi (optarg); break; 149 case 's': 150 section_separator = strdup (optarg); break; 151 } 152 } 153 154 if (show_version) 155 { 156 printf (APPNAME " version " VERSION "\n"); 157 printf ("Copyright (c)2013-2024 Kevin Boone and contributors\n"); 158 printf ("Distributed under the terms of the GNU Public Licence, v3.0\n"); 159 exit (0); 160 } 161 162 if (show_help) 163 { 164 printf ("Usage: %s [options] {files...}\n", argv[0]); 165 printf (" -a,--ascii try to output ASCII only\n"); 166 printf (" -c,--calibre show Calibre metadata (with -m)\n"); 167 printf (" -h,--help show this message\n"); 168 printf (" -l,--log=N set log level, 0-4\n"); 169 printf (" -m,--meta dump document metadata\n"); 170 printf (" -n,--noansi don't output ANSI terminal codes\n"); 171 printf (" --notext don't output document body\n"); 172 printf (" -r,--raw no formatting at all\n"); 173 printf (" -s,--separator=text section separator text\n"); 174 printf (" -v,--version show version\n"); 175 printf (" -w,--width=N set output width\n"); 176 exit (0); 177 } 178 179 if (optind == argc) 180 { 181 fprintf (stderr, "%s: no files selected\n", argv[0]); 182 fprintf (stderr, "'%s --help' for usage\n", argv[0]); 183 exit (-1); 184 } 185 186 Epub2TxtOptions options; 187 memset (&options, 0, sizeof (options)); 188 options.width = width; 189 options.ascii = ascii; 190 options.meta = meta; 191 options.notext = notext; 192 options.calibre = calibre; 193 options.section_separator = section_separator; 194 195 if (is_a_tty) 196 options.ansi = TRUE; 197 if (noansi) 198 options.ansi = FALSE; 199 200 options.raw = raw; 201 202 signal (SIGPIPE, sig_handler); 203 signal (SIGQUIT, sig_handler); 204 signal (SIGINT, sig_handler); 205 signal (SIGHUP, sig_handler); 206 207 int i; 208 for (i = optind; i < argc; i++) 209 { 210 const char *file = argv[i]; 211 char *error = NULL; 212 epub2txt_do_file (file, &options, &error); 213 if (error) 214 { 215 fprintf (stderr, "%s: %s\n", argv[0], error); 216 free (error); 217 } 218 } 219 220 if (section_separator) free (section_separator); 221 exit (0); 222 } 223