| #! /bin/sh -e |
| |
| # |
| # COPYRIGHT |
| # The gcobc program is in public domain. |
| # If it breaks then you get to keep both pieces. |
| # |
| # This file emulates the GnuCOBOL cobc compiler to a limited degree. |
| # For options that can be "mapped" (see migration-guide.1), it accepts |
| # cobc options, changing them to the gcobol equivalents. Options not |
| # recognized by the script are passed verbatim to gcobol, which will |
| # reject them unless of course they are gcobol options. |
| # |
| # User-defined variables, and their defaults: |
| # |
| # Variable Default Effect |
| # echo none If defined, echo the gcobol command |
| # gcobcx none Produce verbose messages |
| # gcobol ./gcobol Name of the gcobol binary |
| # GCOBCUDF PREFIX/share/cobol/udf/ Location of UDFs to be prepended to input |
| # |
| # By default, this script includes all files in $GCOBCUDF. To defeat |
| # that behavior, use GCOBCUDF=none. |
| # |
| # A list of supported options is produced with "gcobc -HELP". |
| # |
| ## Maintainer note. In modifying this file, the following may make |
| ## your life easier: |
| ## |
| ## - To force the script to exit, either set exit_status to 1, or call |
| ## the error function. |
| ## - As handled options are added, add them to the HELP here-doc. |
| ## - The compiler can produce only one kind of output. In this |
| ## script, that's known by $mode. Options that affect the type of |
| ## output set the mode variable. Everything else is appended to the |
| ## opts variable. |
| ## |
| ## - -fPIC is added to the command line if $mode is "-shared". That |
| ## option applies only to "certain machines", per the gcc info |
| ## manual. For this script to be portable across machines, -fPIC |
| ## would have to be set more judiciously. |
| |
| if [ "$COBCPY" ] |
| then |
| copydir="-I$COBCPY" |
| fi |
| |
| if [ "$COB_COPY_DIR" ] |
| then |
| copydir="-I$COB_COPY_DIR" |
| fi |
| |
| # TODO: this file likely needs to query gcobol for its shared path instead |
| udf_default="${0%/*}/../share/gcobol/udf" |
| if [ ! -d "$udfdir" ] |
| then |
| # the one above is the installed one from the packages this one was previously used |
| udf_default="${0%/*}/../share/cobol/udf" |
| fi |
| udfdir="${GCOBCUDF:-$udf_default}" |
| |
| if [ -d "$udfdir" ] |
| then |
| for F in "$udfdir"/* |
| do |
| if [ -f "$F" ] |
| then |
| includes="$includes -include $F " |
| fi |
| done |
| else |
| if [ "${GCOBCUDF:-none}" != "none" ] |
| then |
| echo warning: no such directory: "'$GCOBCUDF'" |
| fi |
| fi |
| |
| exit_status=0 |
| skip_arg= |
| opts="$copydir $includes" |
| mode=-shared |
| |
| incomparable="has no comparable gcobol option" |
| |
| if [ "${gcobcx:-0}" -gt 1 ] |
| then |
| set -x |
| fi |
| |
| error() { |
| echo "error: $1" >&2 |
| exit_status=1 |
| } |
| warn() { |
| echo "warning: $1 ignored" >&2 |
| } |
| ignore_arg() { |
| warn "$1" |
| skip_arg="$1" |
| } |
| no_warn() { :; } # silence is golden |
| |
| help() { |
| cat<<EOF |
| $0 recognizes the following GnuCOBOL cobc output mode options: |
| -b, -c, -m, -S, -x |
| $0 recognizes the following GnuCOBOL cobc compilation options: |
| -C |
| -d, --debug |
| -D |
| -A |
| -Q |
| -E |
| -g |
| --coverage |
| -ext |
| -fec=exception-name, -fno-ec=exception-name |
| -fformat |
| --fixed |
| -F, --free |
| -fimplicit-init |
| -h, --help |
| -save-temps= |
| -save-temps |
| -std=mvs -std=mvs-strict |
| -std=mf -std=mf-strict |
| -std=cobol85 -std=cobol2002 -std=cobol2014 |
| Options that are the same in gcobol and cobc are passed through verbatim. |
| Options that have no analog in gcobol produce a warning message. |
| To produce this message, use -HELP. |
| To see the constructed cobc command-line, use -echo. |
| To override the default cobc, set the "cobc" environment variable. |
| By default, gcobc invokes the gcobol the same directory the gcobc resides. |
| To override, set the gcobol environment variable. |
| EOF |
| } |
| |
| dialect="mf gnu" |
| out_set="" |
| first="" |
| |
| # |
| # Iterate over the command-line tokens. We can't use getopts here |
| # because it's not designed for single-dash words (e.g. -shared). |
| # |
| for opt in "$@" |
| do |
| if [ "$skip_arg" ] |
| then |
| skip_arg= |
| continue |
| fi |
| |
| if [ "$pending_arg" ] |
| then |
| case $pending_arg in |
| -o) output_name="$opt" # capture named output file |
| ;; |
| esac |
| |
| opts="$opts $pending_arg$opt" |
| pending_arg= |
| continue |
| fi |
| |
| case $opt in |
| |
| # pass next parameter to GCC |
| -A) |
| pending_arg=" " |
| ;; |
| |
| # pass next parameter to linker |
| -Q) |
| pending_arg=-Wl, |
| ;; |
| |
| -b) mode="-shared" |
| ;; |
| -c) mode="-c" |
| ;; |
| --conf=*) warn "$opt" |
| ;; |
| -C) error "$opt $incomparable" |
| ;; |
| -d | -debug | --debug) opts="$opts -fcobol-exceptions=EC-ALL" |
| warn "$opt implies -fstack-check:" |
| ;; |
| # define for preprocessor, note: -D* is directly passed |
| -D) |
| pending_arg=$opt |
| ;; |
| -E) opts="$opts $opt -fsyntax-only" |
| ;; |
| -echo) echo="echo" |
| ;; |
| |
| -fec=* | -fno-ec=*) |
| opt="$(echo "$opt" | sed -E 's/-f(no-)?ec=/-f\1cobol-exceptions=EC-/g')" |
| opts="$opts $opt" |
| ;; |
| -ext) |
| pending_arg="$opt " |
| ;; |
| -ext=*) opts="$opts $(echo "$opt" | sed 's/-ext=/-copyext ./')" |
| ;; |
| # A.3 Compiler options |
| -fsign=*) warn "$opt" ;; |
| -ffold-copy=*) warn "$opt" ;; |
| -ffold-call=*) warn "$opt" ;; |
| -fmax-errors=*) warn "$opt" ;; |
| -fintrinsics=*) warn "$opt" ;; |
| -fdump=*) warn "$opt" ;; |
| -fcallfh=*) warn "$opt" ;; |
| -fsqlschema=*) warn "$opt" ;; |
| -fsql) warn "$opt" ;; |
| -fno-recursive-check) no_warn "$opt" ;; |
| -fstack-extended) warn "$opt" ;; |
| -fno-remove-unreachable) no_warn "$opt" ;; |
| -finline-intrinsic) warn "$opt" ;; |
| -ftrace) warn "$opt" ;; |
| -ftraceall) warn "$opt" ;; |
| -fsymtab) warn "$opt" ;; |
| # -fsyntax-only is identical |
| -fdebugging-line) warn "$opt" ;; |
| -fsource-location) warn "$opt" ;; |
| -fstack-check) warn "$opt" ;; |
| -fsection-exit-check) warn "$opt" ;; |
| -fimplicit-goback-check) warn "$opt" ;; |
| -fwrite-after) warn "$opt" ;; |
| -fmfcomment) warn "$opt" ;; |
| -facucomment) warn "$opt" ;; |
| -fno-trunc) no_warn "$opt" ;; |
| -fsingle-quote) warn "$opt" ;; |
| -foptional-file) warn "$opt" ;; |
| -fstatic-call | -fno-static-call) |
| opts="$opts $opt" |
| static_used="x" |
| ;; |
| -fno-gen-c-decl-static-call) no_warn "$opt" ;; |
| -fmf-files) warn "$opt" ;; |
| -ffile-format=*) warn "$opt" ;; |
| -fno-theaders) no_warn "$opt" ;; |
| -fno-tsource) no_warn "$opt" ;; |
| -fno-tmessages) no_warn "$opt" ;; |
| -ftsymbols) warn "$opt" ;; |
| -fdatamap) warn "$opt" ;; |
| -fno-diagnostics-show-option) no_warn "$opt" ;; |
| -fibmcomp) warn "$opt" ;; |
| -fno-ibmcomp) no_warn "$opt" ;; |
| |
| # A.4 Compiler dialect configuration options |
| -fname=*) warn "$opt" ;; |
| -freserved-words=*) warn "$opt" ;; |
| -ftab-width=*) warn "$opt" ;; |
| -ftext-column=*) warn "$opt" ;; |
| -fpic-length=*) warn "$opt" ;; |
| -fword-length=*) warn "$opt" ;; |
| -fliteral-length=*) warn "$opt" ;; |
| -fnumeric-literal-length=*) warn "$opt" ;; |
| -fdefaultbyte=*) warn "$opt" ;; |
| -falign-record=*) warn "$opt" ;; |
| -fkeycompress=*) warn "$opt" ;; |
| -falign-opt) warn "$opt" ;; |
| -fbinary-size=*) warn "$opt" ;; |
| -fbinary-byteorder=*) warn "$opt" ;; |
| -fassign-clause=*) warn "$opt" ;; |
| -fscreen-section-rules=*) warn "$opt" ;; |
| -fdpc-in-data=*) warn "$opt" ;; |
| -ffilename-mapping) warn "$opt" ;; |
| -fpretty-display) warn "$opt" ;; |
| -fbinary-truncate | -fno-binary-truncate) warn "$opt" ;; |
| -fcomplex-odo) warn "$opt" ;; |
| -fodoslide) warn "$opt" ;; |
| -findirect-redefines) warn "$opt" ;; |
| -flarger-redefines-ok) warn "$opt" ;; |
| -frelax-syntax-checks) warn "$opt" ;; |
| -fref-mod-zero-length) warn "$opt" ;; |
| -frelax-level-hierarchy) warn "$opt" ;; |
| -flocal-implies-recursive) warn "$opt" ;; |
| -fsticky-linkage) warn "$opt" ;; |
| -fmove-ibm) warn "$opt" ;; |
| -fperform-osvs) warn "$opt" ;; |
| -farithmetic-osvs) warn "$opt" ;; |
| -fconstant-folding) warn "$opt" ;; |
| -fhostsign) warn "$opt" ;; |
| -fprogram-name-redefinition) warn "$opt" ;; |
| -faccept-update) warn "$opt" ;; |
| -faccept-auto) warn "$opt" ;; |
| -fconsole-is-crt) warn "$opt" ;; |
| -fno-echo-means-secure) no_warn "$opt" ;; |
| -fline-col-zero-default) warn "$opt" ;; |
| -freport-column-plus) warn "$opt" ;; |
| -fdisplay-special-fig-consts) warn "$opt" ;; |
| -fbinary-comp-1) warn "$opt" ;; |
| -fnumeric-pointer) warn "$opt" ;; |
| -fmove-non-numeric-lit-to-numeric-is-zero) warn "$opt" ;; |
| -fimplicit-assign-dynamic-var) warn "$opt" ;; |
| -fcomment-paragraphs=*) warn "$opt" ;; |
| -fmemory-size-clause=*) warn "$opt" ;; |
| -fmultiple-file-tape-clause=*) warn "$opt" ;; |
| -flabel-records-clause=*) warn "$opt" ;; |
| -fvalue-of-clause=*) warn "$opt" ;; |
| -fdata-records-clause=*) warn "$opt" ;; |
| -ftop-level-occurs-clause=*) warn "$opt" ;; |
| -fsame-as-clause=*) warn "$opt" ;; |
| -ftype-to-clause=*) warn "$opt" ;; |
| -fusage-type=*) warn "$opt" ;; |
| -fsynchronized-clause=*) warn "$opt" ;; |
| -fsync-left-right=*) warn "$opt" ;; |
| -fspecial-names-clause=*) warn "$opt" ;; |
| -fgoto-statement-without-name=*) warn "$opt" ;; |
| -fstop-literal-statement=*) warn "$opt" ;; |
| -fstop-identifier-statement=*) warn "$opt" ;; |
| -fdebugging-mode=*) warn "$opt" ;; |
| -fuse-for-debugging=*) warn "$opt" ;; |
| -fpadding-character-clause=*) warn "$opt" ;; |
| -fnext-sentence-phrase=*) warn "$opt" ;; |
| -flisting-statements=*) warn "$opt" ;; |
| -ftitle-statement=*) warn "$opt" ;; |
| -fentry-statement=*) warn "$opt" ;; |
| -fmove-noninteger-to-alphanumeric=*) warn "$opt" ;; |
| -foccurs-max-length-without-subscript) warn "$opt" ;; |
| -flength-in-data-division) warn "$opt" ;; |
| -fmove-figurative-constant-to-numeric=*) warn "$opt" ;; |
| -fmove-figurative-space-to-numeric=*) warn "$opt" ;; |
| -fmove-figurative-quote-to-numeric=*) warn "$opt" ;; |
| -fodo-without-to=*) warn "$opt" ;; |
| -fodo-last-varlen=*) warn "$opt" ;; |
| -fsection-segments=*) warn "$opt" ;; |
| -falter-statement=*) warn "$opt" ;; |
| -fcall-overflow=*) warn "$opt" ;; |
| -fnumeric-boolean=*) warn "$opt" ;; |
| -fhexadecimal-boolean=*) warn "$opt" ;; |
| -fnational-literals=*) warn "$opt" ;; |
| -fhexadecimal-national-literals=*) warn "$opt" ;; |
| -fnational-character-literals=*) warn "$opt" ;; |
| -fhp-octal-literals=*) warn "$opt" ;; |
| -facu-literals=*) warn "$opt" ;; |
| -fword-continuation=*) warn "$opt" ;; |
| -fnot-exception-before-exception=*) warn "$opt" ;; |
| -faccept-display-extensions=*) warn "$opt" ;; |
| -frenames-uncommon-levels=*) warn "$opt" ;; |
| -fsymbolic-constant=*) warn "$opt" ;; |
| -fconstant-78=*) warn "$opt" ;; |
| -fconstant-01=*) warn "$opt" ;; |
| -fperform-varying-without-by=*) warn "$opt" ;; |
| -freference-out-of-declaratives=*) warn "$opt" ;; |
| -freference-bounds-check=*) warn "$opt" ;; |
| -fprogram-prototypes=*) warn "$opt" ;; |
| -fcall-convention-mnemonic=*) warn "$opt" ;; |
| -fcall-convention-linkage=*) warn "$opt" ;; |
| -fnumeric-value-for-edited-item=*) warn "$opt" ;; |
| -fincorrect-conf-sec-order=*) warn "$opt" ;; |
| -fdefine-constant-directive=*) warn "$opt" ;; |
| -ffree-redefines-position=*) warn "$opt" ;; |
| -frecords-mismatch-record-clause=*) warn "$opt" ;; |
| -frecord-delimiter=*) warn "$opt" ;; |
| -fsequential-delimiters=*) warn "$opt" ;; |
| -frecord-delim-with-fixed-recs=*) warn "$opt" ;; |
| -frecord-sequential-advancing=*) warn "$opt" ;; |
| -fmissing-statement=*) warn "$opt" ;; |
| -fzero-length-literals=*) warn "$opt" ;; |
| -fxml-generate-extra-phrases=*) warn "$opt" ;; |
| -fcontinue-after=*) warn "$opt" ;; |
| -fgoto-entry=*) warn "$opt" ;; |
| -fdepending-on-not-fixed=*) warn "$opt" ;; |
| -fbinary-sync-clause=*) warn "$opt" ;; |
| -fnonnumeric-with-numeric-group-usage=*) warn "$opt" ;; |
| -fassign-variable=*) warn "$opt" ;; |
| -fassign-using-variable=*) warn "$opt" ;; |
| -fassign-ext-dyn=*) warn "$opt" ;; |
| -fassign-disk-from=*) warn "$opt" ;; |
| -fvsam-status=*) warn "$opt" ;; |
| -fself-call-recursive=*) warn "$opt" ;; |
| |
| # TODO: create a temporary COBOL file with COBOL-WORDS directives |
| # and force-include it |
| -fnot-reserved=*) warn "$opt" ;; |
| -freserved=*) warn "$opt" ;; |
| -fnot-register=*) warn "$opt" ;; |
| -fregister=*) warn "$opt" ;; |
| |
| -fformat=auto) ;; # gcobol and gnucobol default |
| |
| -fixed | --fixed | -fformat=fixed | -fformat=variable | -fformat=xcard) |
| # note: variable + xcard are only _more similar_ to fixed than free, |
| # (with changing right-column to 250/255, which isn't supported in gcobol, yet) |
| opts="$opts -ffixed-form" |
| ;; |
| |
| -F | -free | --free | -fformat=free | -fformat=*) |
| # note: "all other formats" are only _more similar_ to free than fixed |
| opts="$opts -ffree-form" |
| ;; |
| -h | --help) opts="$opts --help" |
| ;; |
| |
| -HELP) help && exit |
| ;; |
| -i | --info) warn "$opt" |
| ;; |
| |
| # -I |
| -fimplicit-init) warn "$opt" |
| ;; |
| -j | -job) warn "$opt" |
| ;; |
| -K) ignore_arg "$opt" |
| ;; |
| -K*) warn "$opt" |
| ;; |
| # -l |
| # -L |
| --list*) warn "$opt" |
| ;; |
| -m) mode="-shared" |
| ;; |
| # -main |
| # -nomain |
| |
| -o) pending_arg=$opt |
| ;; |
| -o*) output_name=$opt ## non-empty means do not infer |
| opts="$opts $opt" |
| ;; |
| |
| # -O0, -Ox |
| -O | -O2 | -Os) warn "$opt" |
| ;; |
| -S) mode="$opt" |
| ;; |
| -save-temps=*) opt="$(echo "$opt" | sed -E 's/^.+=//')" |
| export GCOBOL_TEMPDIR="$opt" |
| ;; |
| -save-temps) export GCOBOL_TEMPDIR="${PWD:-$(pwd)}" |
| ;; |
| # -shared is identical |
| |
| -std=mvs | -std=mvs-strict | -std=ibm | -std=ibm-strict) dialect=ibm |
| ;; |
| -std=mf | -std=mf-strict) dialect=mf |
| ;; |
| # GnuCOBOL's default and GCC's dialect for GnuCOBOL |
| -std=default) dialect=gnu |
| ;; |
| # GCC COBOL targets COBOL2024 "mostly backward to COBOL85" |
| -std=cobol*) dialect="" |
| ;; |
| -std=*) |
| dialect="" |
| warn "$opt (unkown dialect)" |
| ;; |
| -P | -P=* | -X | --Xref) |
| warn "$opt (no listing)" |
| ;; |
| -t | -T) |
| # note: -P has an _optional_ arg, so we leave it above |
| ignore_arg "$opt (no listing)" |
| ;; |
| -q | --brief) warn "$opt" |
| ;; |
| -v | --verbose) opts="$opts -V" |
| ;; |
| # note: we want -dumpversion to be passed to gcc |
| -V | --version | -version) opts="$opts --version" |
| ;; |
| # pass through, strangely -Wall is not supported |
| -w | -W | -Wextra) opts="$opts $opt" |
| ;; |
| -Wno-*) no_warn "$opt" |
| ;; |
| |
| -W*) ignore_arg "$opt" |
| ;; |
| |
| -x) mode= |
| ;; |
| |
| -) output_name=a.out # nonnull to prevent overriding gcc default |
| opts="$opts /dev/stdin" |
| ;; |
| |
| # First file name argument is default output filename. |
| *) if [ -z "$output_name" -a -e "$opt" ] |
| then |
| output_name=$(basename "${opt%.*}") |
| case $mode in |
| -c) output_name="$output_name".o |
| ;; |
| -shared) |
| output_name="$output_name".so |
| opts="$opts -fPIC" |
| ;; |
| esac |
| opts="$opts -o $output_name" |
| fi |
| opts="$opts $opt" # pass through |
| ;; |
| esac |
| done |
| |
| # cobc default: |
| if [ "$static_used" = "" ] |
| then |
| opts="$opts -fno-static-call"; |
| fi |
| |
| if [ "$exit_status" -gt 0 ] |
| then |
| exit $exit_status |
| fi |
| |
| # To override the default gcobol, set the "gcobol" environment variable. |
| gcobol="${gcobol:-${0%/*}/gcobol}" |
| |
| if [ "$dialect" ] |
| then |
| dialect=$(echo $dialect | sed -E 's/[[:alnum:]]+/-dialect &/g') |
| fi |
| |
| if [ "$echo" ] |
| then |
| echo $gcobol $mode $opts |
| exit |
| fi |
| |
| if [ "$gcobcx" ] |
| then |
| set -x |
| fi |
| |
| exec $gcobol $mode $dialect $opts |