diff --git a/README.md b/README.md index ff04a70..27a7da3 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,14 @@ ical2rem [OPTION]… FILE… Output goes to stdout and can be redirected to a `.rem` file. +Pass `-` as a filename to read from standard input. `-` may appear at most once, +but can be freely mixed with regular files: + +```bash +curl https://example.com/calendar.ics | ical2rem - > calendar.rem +ical2rem work.ics - personal.ics > all.rem +``` + ### Examples Convert a single calendar: @@ -99,6 +107,11 @@ Strip all metadata lines from output: ical2rem --no-uuid --no-source --no-location --no-description --no-conference-url personal.ics ``` +Use stdin as input calendar: +```bash +curl https://example.com/calendar.ics | ical2rem - > calendar.rem +``` + Override calendar name in `INFO` lines (single file only): ```bash ical2rem --source "Work" work.ics > work.rem @@ -113,7 +126,7 @@ ical2rem --verbose personal.ics > personal.rem | Option | Description | |---|---| -| `FILE…` | One or more `.ics` files to convert | +| `FILE…` | One or more `.ics` files to convert; use `-` for standard input (at most once) | | `-z`, `--timezone TZ` | Target timezone for output (default: local) | | `--sort asc\|desc\|original` | Sort order by date (default: `desc`); `original` preserves processing order (sorted by UID within each file, last file first) | | `--source NAME` | Override calendar name (single file only) | diff --git a/bin/main.ml b/bin/main.ml index 8ae8771..1faa0b4 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -14,7 +14,22 @@ let read_file filename = close_in ic; Bytes.unsafe_to_string s +let read_stdin () = + let buf = Buffer.create 4096 in + (try + while true do + Buffer.add_channel buf stdin 4096 + done + with End_of_file -> ()); + Buffer.contents buf + let ical2rem (args : CommandLine.cli_args) ical_files = + (* Validate: '-' (stdin) may appear at most once *) + let stdin_count = List.length (List.filter (( = ) "-") ical_files) in + if stdin_count > 1 then begin + Printf.eprintf "Error: '-' (stdin) may appear at most once.\n"; + exit 1 + end; (* Validate --source with multiple files *) (match args.source with | Some _ when List.length ical_files > 1 -> @@ -31,11 +46,17 @@ let ical2rem (args : CommandLine.cli_args) ical_files = let good_rems = ListLabels.fold_left ~init:[] ical_files ~f:(fun good_rems_acc filename -> try - let file_content = read_file filename in - let basename = - match args.source with - | Some name -> name - | None -> Filename.remove_extension (Filename.basename filename) + let file_content, basename = + if filename = "-" then + ( read_stdin (), + match args.source with + | Some name -> name + | None -> "stdin" ) + else + ( read_file filename, + match args.source with + | Some name -> name + | None -> Filename.remove_extension (Filename.basename filename) ) in match Icalendar.parse file_content with | Error e ->