From 415a698df55109d70edb0e77104255450a68fd5c Mon Sep 17 00:00:00 2001 From: Frank Halasz Date: Thu, 9 May 2024 21:31:27 -0700 Subject: [PATCH] Overhaul of loadup scripts (#1699) * Make medley.sh and its associated scripts POSIX compliant - i.e., debashify them * Added config file for medley script, medley now reads from config file and prepends arguemnts from file to the copmmand line arguments * WIP. Updates to medley.sh scripts. * WIP. More on medley.sh and friends update. * WIP. Medley redo * WIP. Debugging new medley scripts * Renamed medley.sh/medley.command to be medley_main.sh. Added code to compile single medley.sh/medley.command script by inlining all of the source'd medley_*.sh files. * Add temp fix for cygwin Issue #1685 * Minor fixup to medley_utils.sh; take debug code out out of run_medley * Add README to medley directory to explain how to compile medley.sh (medley.command). * Ooops. This time really adding the README file to the medley directory explaining how to compile medley.sh (medley.command) * Update loadup- scripts to use updated medley scripts rather than run-medley * Fix default setting of $config_file in medley_configfile.sh * Redo medley compile to pick up last commikt * Fixing how maiko exe is found and sysout argument error processing - both issues discovered testing on MAcOS * In medley_configfile, replace echo with printf %s because echo - does not work in zsh * Supress config file on loadups calls to Medley * Add oldschool support (use original run-medley) to loadup scripts; improve FAILURE detection so loadup-all won't proceed once one of the components fails * Add in medley_args.sh add -prog as synonym to --maikoprog to aid in loadup scripts; in medley_run.sh script try to get a good exit code for call to maiko, especially useful for loadup scripts * Run loadup scripts thru shellcheck and update as necessary to make Posix compliant * Get rid of -nt comparisons in loadup-setup.sh because they are not posix-complaint. They were not really needed anyway. * Removing (for now) use of lde exit codes to decide FAILURE case in loadup-setup.sh since exit codes from lde apperar to be inverted on MacOS. * Update medley man page. Add - functionality to more args is medley_args.sh * Compile medley.sh with changes from last commit * Ooops. Left medley_args.sh changes out of last commit. Rectifying here. * Added support for LDEKEYBOARDTYPE to medley_run to match run-medley * Add to medley.sh: auto numbered id's and titles with id's inserted * Cleanup some shellcheck issues in medley_main.sh * fix maiko args -nh-xxx. were -nethub-xxxx. In medley_run.sh * Overhaul handling of pass-on args to manage the quoting issues prevelant in the previous implementation * Cleanup minor shellcheck issues in medley_*.sh scripts * Add underscore as character allowed in ids - makes things clearer when id used with + * Add a self-numbering id to medley calls in loadup scripts * Put workaround in medley_run.sh for Issue #1702 - issues with sysout arg processing in Maiko * Oops. messed up LDESRCSYSOUT in last commit. should be LDESOURCESYSOUT * compile medley.sh --- docs/man-page/man_medley.html | 112 +- docs/man-page/medley.1 | 293 +++-- docs/man-page/medley.1.gz | Bin 3144 -> 4418 bytes docs/man-page/medley.1.md | 154 ++- run-medley | 3 + scripts/loadup-all.sh | 32 +- scripts/loadup-apps-from-full.sh | 35 +- scripts/loadup-aux.sh | 11 +- scripts/loadup-db-from-full.sh | 11 +- scripts/loadup-db.sh | 10 +- scripts/loadup-full-from-lisp.sh | 13 +- scripts/loadup-full.sh | 12 +- scripts/loadup-init.sh | 11 +- scripts/loadup-lisp-from-mid.sh | 11 +- scripts/loadup-mid-from-init.sh | 16 +- scripts/loadup-setup.sh | 89 +- scripts/medley/README | 6 + scripts/medley/compile.sh | 5 + scripts/medley/inline.sh | 460 ++++++++ scripts/medley/medley.command | 1657 +++++++++++++++++++++++++-- scripts/medley/medley_args.sh | 330 ++++-- scripts/medley/medley_configfile.sh | 78 ++ scripts/medley/medley_geometry.sh | 71 +- scripts/medley/medley_header.sh | 28 + scripts/medley/medley_main.sh | 207 ++++ scripts/medley/medley_run.sh | 320 ++++++ scripts/medley/medley_usage.sh | 64 +- scripts/medley/medley_utils.sh | 185 +-- scripts/medley/medley_vnc.sh | 273 ++--- 29 files changed, 3728 insertions(+), 769 deletions(-) create mode 100644 scripts/medley/README create mode 100755 scripts/medley/compile.sh create mode 100755 scripts/medley/inline.sh create mode 100644 scripts/medley/medley_configfile.sh create mode 100644 scripts/medley/medley_header.sh create mode 100755 scripts/medley/medley_main.sh create mode 100644 scripts/medley/medley_run.sh diff --git a/docs/man-page/man_medley.html b/docs/man-page/man_medley.html index 44149e06..4f561a5e 100644 --- a/docs/man-page/man_medley.html +++ b/docs/man-page/man_medley.html @@ -7,101 +7,113 @@

OPTIONS

MEDLEYDIR is an environment variable set by Medley and used by many of the options described below. MEDLEYDIR is the top level directory of the Medley installation that contains the specific medley script that is invoked after all symbolic links are resolved. In the standard global installation this will be /usr/local/interlisp/medley. But Medley can be installed in multiple places on any given machine and hence MEDLEYDIR is computed on each invocation of medley.

Flags

-
-
-h, --help
+
-h, --help

Prints out a brief summary of the flags and arguments to medley.

-
-z, --man
+
-z, --man

Show the man page for medley

-
-f, --full
+
-c [FILE | -], --config [FILE | -]
+

Use FILE as the config file for this run of Medley. See information on CONFIG FILE below. If FILE is “-”, then suppress the use of a config file for this run of Medley.

+
+
-f, --full

Start Medley from the standard “full” sysout. full.sysout includes a complete Interlisp and CommonLisp environment with a standard set of development tools. It does not include any of the applications built using Medley. (See SYSOUT_FILE below for more information on starting sysouts.)

-
-l, --lisp
+
-l, --lisp

Start Medley from the standard “lisp” sysout. lisp.sysout only includes the basic Interlisp and CommonLisp environment. (See SYSOUT_FILE below for more information on starting sysouts.)

-
-a, --apps
+
-a, --apps

Start Medley from the standard “apps” sysout. apps.sysout includes everything in full.sysout plus Medley applications including Notecards, Rooms and CLOS. It also includes pre-installed links to key Medley documentation. (See SYSOUT_FILE below for more information on starting sysouts.)

-
-e, --interlisp (relevent only when --apps is specified)
-

Make the initial Exec window within Medley be an Interlisp Exec. Default is to start in an XCL Exec.

+
-u, --continue
+

Nullify any prior setting of the sysout file (e.g., from the config file) - causing Medley to start from the virtual memory file resulting from the previous invocation (with the same values for –id and –logindir), if any. If there is no matching virtual memory file, Medley will start from the full.sysout (see -f/–full above). Equivalent to “-y -”. (See SYSOUT FILE section below.)

-
-n, --noscroll
-

Ordinarily Medley displays scroll bars to enable the user to pan the Medley virtual display within the Medley window. This is true even when the entire virtual display fits within the window. Specifying --noscroll turns off the scroll bars. Note: If --noscroll is specified and the virtual screen is larger than the window, there will be no way to pan to the non-visible parts of the virtual display.

+
-y [SYSOUT_FILE | -], --sysout [SYSOUT-FILE | -]
+

Start Medley from the specified SYSOUT-FILE. This is an alternative to specifying the SYSOUT-FILE as the last argument on the command line (but before any PASS_ON_ARGS). It can be used to specify the SYSOUT-FILE in the config file (see information on CONFIG FILE below). If SYSOUT-FILE is “-”, then any prior setting of the sysout file (e.g., from the config file) is nullified (see -u/–continue above). (See SYSOUT FILE section below.)

-
-g WxH, --geometry WxH
-

Sets the size of the X Window (or VNC window) that Medley runs in to be Width x Height. (Full X Windows geomtery specification with +X+Y is not currently supported). If --geometry is not specified but --screensize is, then the window size will be determined based on the --screensize values and the --noscroll flag. If neither --geometry nor --screensize is provided, then the window size is set to 1440x900 if --noscroll is set and 1462x922 if --noscroll is not set.

+
-e [+ | -], --interlisp [+ | -]
+

If value is “+” or no value, make the initial Exec window within Medley be an Interlisp Exec. If value is “-”, make the initial Exec window be the default XCL Exec. This flag applies only when the –apps flag is used.

-
-s WxH, --screensize WxH
-

Sets the size of the virtual display as seen from Medley’s point of view. The Medley window is an unscaled viewport onto this virtual display. If --screensize is not specified but --geometry is, then the virtual display size will be set so that the entire virtual display fits into the given window geometry. If neither --screensize nor --geometry is provided, then the screen size is set to 1440x900.

+
-n [+ | -], --noscroll [+ | -]
+

Medley ordinarily displays scroll bars to enable the user to pan the Medley virtual display within the Medley window. This is true even when the entire virtual display fits within the window. Specifying “-n +” (–noscroll +) turns off scroll bars. Specifying “-n -” (–scroll -) turns on scroll bars. Specifying -n (–noscroll) with no value is equivalent to specifying “–noscroll +”. Default is scroll bars off. Note: If scroll bars are off and the virtual screen is larger than the window, there will be no way to pan to the non-visible parts of the virtual display.

-
-t STRING, --title STRING
-

Use STRING as title of Medley window. Ignored when when the --vnc flag is set or when running on Windows (Docker) installations.

+
-g [WxH | -], --geometry [WxH | -]
+

Sets the size of the X Window (or VNC window) that Medley runs in to be Width x Height. (Full X Windows geomtery specification with +X+Y is not currently supported). If a value of “-” is given, geometry is set to the default value. If --geometry is not specified but --screensize is, then the window size will be determined based on the --screensize values and the --noscroll flag. If neither --geometry nor --screensize is provided, then the window size is set to 1440x900 if --noscroll is set and 1462x922 if --noscroll is not set. (Also see note below under CONFIG FILE on the use of geometry and screensize in config files.)

-
-d :N, --display :N ** Not applicable to Windows (Docker) installations **
-

Use X display :N. Defaults to the value of $DISPLAY. This flag is ignored when the --vnc flag is set as well as on Windows (Docker) installations.

+
-s [WxH | -], --screensize [WxH | -]
+

Sets the size of the virtual display as seen from Medley’s point of view. If a value of “-” is given, screensize is set to the default value. The Medley window is an unscaled viewport onto this virtual display. If --screensize is not specified but --geometry is, then the virtual display size will be set so that the entire virtual display fits into the given window geometry. If neither --screensize nor --geometry is provided, then the screen size is set to 1440x900. (Also see note below under CONFIG FILE on the use of geometry and screensize in config files.)

-
-v, --vnc ** Applicable only to WSL installations **
-

Use a VNC window running on the Windows side instead of an X window. The VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well. This flag is always set for WSL1 installations.

+
-ps [N | -], –pixelscale [N | -] ** Applicable only when display is SDL-based (e.g., on Windows/Cygwin) **
+

Sets the pixel scaling factor to N. If value of “-” is given, the pixel scale factor is set to its default of 1.

-
-i [ID_STRING | - | --], --id [ID_STRING | - | --]
-

Use ID_STRING as the id for this run of Medley, iunless ID_STRING is “-” or “--”. If ID_STRING is “-”, then use the basename of $MEDLEYDIR as the id. If ID_STRING is “--”, then use the basename of the parent directory of $MEDLEYDIR as the id. Only one instance of Medley with a given id can run at a time. The id is used to distinguish the virtual memory stores so that multiple instances of Medley can run simultaneously. Default id is “default”.

+
-t [STRING | -], --title [STRING | -]
+

Use STRING as title of Medley window. If the value of “-” is given, sets the title to its default value (“Medley Interlisp”). Ignored when when the --vnc flag is set.

-
-m N, --mem N
-

Set Medley to run in N MB of virtual memory. Defaults to 256MB.

+
-d [:N | -], --display [:N | -]
+

Use X display :N. If value is “-”, reset display to its default value. Default value is the value of $DISPLAY. On platforms that support X Windows as well as SDL, the value of -d (–display) should be set to “SDL” to select using SDL instead of X Windows. This flag is ignored on the Windows/Cygwin platform and when the --vnc flag is set on Windows System for Linux.

-
-p FILE, --vmem FILE
-

Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. The --id flag will not protect against vmem collisions when the --vmem flag is used. Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this Medley run (see --id flag above). See --logindir below for setting of LOGINDIR. On Windows (Docker) installations, FILE is specified in the Medley file system, not the host Windows file system.

+
-v [+ | -] , --vnc [+ | -] ** Applicable only to WSL installations **
+

If value is “+” or no value is given, then use a VNC window running on the Windows side instead of an X window. If value is “-”, then do not use a VNC window, relying instead on a standard X Window. A VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well. This flag is always set for WSL1 installations.

-
-r [FILE | -], --greet [FILE | -]
-

Use FILE as the Medley greetfile, unless FILE is “-” in which case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, except when the --apps flag is used in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. On Windows (Docker) installations, FILE is specified in the Medley file system, not the host Windows file system.

+
-i [ID_STRING | - | --], --id [ID_STRING | - | --]
+

Use ID_STRING as the id for this run of Medley, unless ID_STRING is “-”, “--”, or “---”. If ID_STRING is “-”, then reset the id to “default” (e.g., if it was previously set in the config file). If ID_STRING is “--”, then use the basename of $MEDLEYDIR as the id. If ID_STRING is “---”, then use the basename of the parent directory of $MEDLEYDIR as the id. Only one instance of Medley with a given id can run at a time. The id is used to distinguish the virtual memory stores so that multiple instances of Medley can run simultaneously. Default id is “default”.

-
-x [DIR | -], --logindir [DIR | -] ** On Linux and WSL installations **
-

Use DIR as LOGINDIR in Medley, unless DIR is “-”, in which case use $MEDLEYDIR/logindir. DIR (or $MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to $HOME/il. LOGINDIR is used by Medley as the working directory on start-up and where it loads any “personal” initialization file from.

+
-m [N | -], --mem [N | -]
+

Set Medley to run in N MB of virtual memory. Defaults to 256MB. If a value of “-” is given, resets to default value.

-
-x [DIR | -], --logindir [DIR | -] ** On Windows (Docker) installations **
-

Map DIR in the Windows host file system to /home/medley/il in the Medley file system (in the Docker container). LOGINDIR is always /home/medley/il from Medley’s standpoint. The “-” value is not valid in this case.

+
-p [FILE | -], --vmem [FILE | -]
+

Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. The --id flag will not protect against vmem collisions when the --vmem flag is used. If the value “-” is given, then resets the vmem file to the default. Default is to store the vmem in LOGINDIR/vmem/lisp_III.virtualmem, where III is the id of this Medley run (see --id flag above). See --logindir below for setting of LOGINDIR.

-
-u, --update ** Windows (Docker) installations only **
-

Before running Medley, do a pull to retrieve the latest interlisp/medley docker image from Docker Hub.

+
-r [FILE | -], --greet [FILE | -]
+

Use FILE as the Medley greetfile, unless FILE is “-” in which case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, except when the --apps flag is used in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. On Windows/Cygwin installations, FILE is specified in the Medley file system, not the host Windows file system.

-
-b, --background ** Windows (Docker) installations only **
-

Run Medley in background rather than foreground.

+
-x [DIR | - | –], --logindir [DIR | - | –]
+

Use DIR as LOGINDIR in Medley. If the value is “–”, use $MEDLEYDIR/logindir as LOGINDIR. If a value of “-” is given, then reset LOGINDIR to its default value. DIR (or $MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to $HOME/il. LOGINDIR is used by Medley as the working directory on start-up and where it loads any “personal” initialization file from. On Windows/Cygwin installations, FILE is specified in the Medley file system, not the host Windows file system.

-
-p PORT, --port PORT ** Windows (Docker) installations only **
-

Use PORT as the port that VNC viewer uses to contact the VNC server within the Docker container. Default is 5900.

+
-nh Host:Port:Mac:Debug, --nethub Host:Port:Mac:Debug
+

Set the parameters for using Nethub XNS networking. Host is the full domain name of the nethub host. Port is the port on Host that nethub is using. Mac is the Mac address that this instance of Medley should use when contacting the nethub host. Debug is the level of nethub debug information that should be printed on stdout (value is 0, 1, or 2). A Host value is required and serves to turn nethub functionality on. Port, Mac and Debug parameters are optional and will default if left off. Finally, if any of the parameters have a value of “-”, any previous setting (e.g., in a config file) for the parameter will be reset to the default value - which in the case of Host is the null string, turning nethub functionality off.

-
-w [DISTRO | -], --wsl [DISTRO | -] ** Windows (Docker) installations only **
-

Run Medley in the context of the named WSL DISTRO instead of within Docker. If DISTRO is “-”, used the default WSL distro. Equivalent to typing “wsl -d DISTRO medley ...” into a Command or Powershell window.

+
-nf, -NF, –nofork
+

No fork. Relevant only to the Medley loadup workflow.

+
+
-prog EXE, –maikoprog EXE
+

Use EXE as the basename of the Maiko executable. Relevant only to the Medley loadup workflow.

+
+
–maikodir DIR
+

Use DIR as the directory containing the Maiko emulator. For testing purposes only.

Other Options

-
-
SYSOUT_FILE
+
SYSOUT_FILE

The pathname of the file to use as a sysout for Medley to start from. If SYSOUT_FILE is not provided and none of the flags (--apps, --full, --lisp) is used, then Medley will start from the saved virtual memory file from the previous session with the same ID_STRING as this run. If no such virtual memory file exists, then Medley will start from the standard full.sysout (equivalent to specifying the --full flag). On Windows (Docker) installations, SYSOUT_FILE is specified in the Medley file system, not the host Windows file system.

-
PASS_ON_ARGS
-

All arguments after the “--” flag, are passed unaltered to lde via run-medley.

+
PASS_ON_ARGS
+

All arguments after the “--” flag, are passed unaltered to the Maiko emulator.

-

FILES

+

CONFIG FILE

+

A config file can be used to “pre-specify” any of the above command line arguments. The config file consists of command line arguments (flags or flag-value pairs), one per line. These arguments are read from the config file and prepended to the arguments actually given on the command line. Since later arguments override earlier arguments, any argument actually given on the command line will override a conflicting argument given in the config file.

+

Unless specified using the -c (–config) argument, the default config file will be $MEDLEYDIR/.medley_config, if it exists, and $HOME/.medley_config, otherwise.

+

Specifying, “-c -” or “–config -” on the command line will suppress the use of config files for the current run of Medley.

+

Note: care must be taken when using -g (–geometry) and/or -s (–screensize) arguments in config files. If only one of these is specified, then the other is conputed. But if both are specified, then the specified dimensions are used as given. Unexpected results can arise if one is specified in the config file but the other is specified on the command line. In this case, the two specified dimensions will be used as given. It will not be the case, as might be expected, that the dimension given in the config file will be overridden by a dimension computed from the dimension given on the command line.

+

OTHER FILES

-
$HOME/il
+
$HOME/il

Default Medley LOGINDIR

-
$HOME/il/vmem/lisp.virtualmem
+
$HOME/il/vmem/lisp.virtualmem

Default virtual memory file

-
$HOME/il/INIT(.LCOM)
+
$HOME/il/INIT(.LCOM)

Default personal init file

-
$MEDLEYDIR/greetfiles/MEDLEYDIR-INIT(.LCOM)
+
$MEDLEYDIR/greetfiles/MEDLEYDIR-INIT(.LCOM)

Default Medley greetfile

BUGS

See GitHub Issues: <https://github.com/Interlisp/medley/issues>

COPYRIGHT

-

Copyright(c) 2023 by Interlisp.org

+

Copyright(c) 2023-2024 by Interlisp.org

diff --git a/docs/man-page/medley.1 b/docs/man-page/medley.1 index a5a0a746..8d7ed767 100644 --- a/docs/man-page/medley.1 +++ b/docs/man-page/medley.1 @@ -1,14 +1,14 @@ -.\" Automatically generated by Pandoc 2.5 +.\" Automatically generated by Pandoc 2.9.2.1 .\" .ad l .TH "MEDLEY" "1" "" "" "Start Medley Interlisp" -.nh \" Turn off hyphenation by default. +.nh .SH NAME .PP \f[B]medley\f[R] \[em] starts up Medley Interlisp .SH SYNOPSIS .PP -\f[B]medley\f[R] [ flags \&... ] [ \f[I]SYSOUT_FILE\f[R] ] [ \-\- +\f[B]medley\f[R] [ flags \&... ] [ \f[I]SYSOUT_FILE\f[R] ] [ -- \f[I]PASS_ON_ARGS\f[R] ] .SH DESCRIPTION .PP @@ -28,13 +28,19 @@ hence MEDLEYDIR is computed on each invocation of medley. .PP \ .TP -.B \-h, \-\-help +-h, --help Prints out a brief summary of the flags and arguments to medley. .TP -.B \-z, \-\-man +-z, --man Show the man page for medley .TP -.B \-f, \-\-full +-c [\f[I]FILE\f[R] | -], --config [\f[I]FILE\f[R] | -] +Use \f[I]FILE\f[R] as the config file for this run of Medley. +See information on \f[I]CONFIG FILE\f[R] below. +If \f[I]FILE\f[R] is \[lq]-\[rq], then suppress the use of a config file +for this run of Medley. +.TP +-f, --full Start Medley from the standard \[lq]full\[rq] sysout. full.sysout includes a complete Interlisp and CommonLisp environment with a standard set of development tools. @@ -42,179 +48,270 @@ It does not include any of the applications built using Medley. (See \f[I]SYSOUT_FILE\f[R] below for more information on starting sysouts.) .TP -.B \-l, \-\-lisp +-l, --lisp Start Medley from the standard \[lq]lisp\[rq] sysout. lisp.sysout only includes the basic Interlisp and CommonLisp environment. (See \f[I]SYSOUT_FILE\f[R] below for more information on starting sysouts.) .TP -.B \-a, \-\-apps +-a, --apps Start Medley from the standard \[lq]apps\[rq] sysout. apps.sysout includes everything in full.sysout plus Medley applications including Notecards, Rooms and CLOS. -It also includes pre\-installed links to key Medley documentation. +It also includes pre-installed links to key Medley documentation. (See \f[I]SYSOUT_FILE\f[R] below for more information on starting sysouts.) .TP -.B \-e, \-\-interlisp (relevent only when \-\-apps is specified) -Make the initial Exec window within Medley be an Interlisp Exec. -Default is to start in an XCL Exec. +-u, --continue +Nullify any prior setting of the sysout file (e.g., from the config +file) - causing Medley to start from the virtual memory file resulting +from the previous invocation (with the same values for \[en]id and +\[en]logindir), if any. +If there is no matching virtual memory file, Medley will start from the +full.sysout (see -f/\[en]full above). +Equivalent to \[lq]-y -\[rq]. +(See \f[I]SYSOUT FILE\f[R] section below.) .TP -.B \-n, \-\-noscroll -Ordinarily Medley displays scroll bars to enable the user to pan the +-y [\f[I]SYSOUT_FILE\f[R] | -], --sysout [\f[I]SYSOUT-FILE\f[R] | -] +Start Medley from the specified \f[I]SYSOUT-FILE\f[R]. +This is an alternative to specifying the \f[I]SYSOUT-FILE\f[R] as the +last argument on the command line (but before any +\f[I]PASS_ON_ARGS\f[R]). +It can be used to specify the \f[I]SYSOUT-FILE\f[R] in the config file +(see information on \f[I]CONFIG FILE\f[R] below). +If \f[I]SYSOUT-FILE\f[R] is \[lq]-\[rq], then any prior setting of the +sysout file (e.g., from the config file) is nullified (see +-u/\[en]continue above). +(See \f[I]SYSOUT FILE\f[R] section below.) +.TP +-e [+ | -], --interlisp [+ | -] +If value is \[lq]+\[rq] or no value, make the initial Exec window within +Medley be an Interlisp Exec. +If value is \[lq]-\[rq], make the initial Exec window be the default XCL +Exec. +This flag applies only when the \[en]apps flag is used. +.TP +-n [+ | -], --noscroll [+ | -] +Medley ordinarily displays scroll bars to enable the user to pan the Medley virtual display within the Medley window. This is true even when the entire virtual display fits within the window. -Specifying \-\-noscroll turns off the scroll bars. -Note: If \-\-noscroll is specified and the virtual screen is larger than -the window, there will be no way to pan to the non\-visible parts of the +Specifying \[lq]-n +\[rq] (\[en]noscroll +) turns off scroll bars. +Specifying \[lq]-n -\[rq] (\[en]scroll -) turns on scroll bars. +Specifying -n (\[en]noscroll) with no value is equivalent to specifying +\[lq]\[en]noscroll +\[rq]. +Default is scroll bars off. +Note: If scroll bars are off and the virtual screen is larger than the +window, there will be no way to pan to the non-visible parts of the virtual display. .TP -.B \-g \f[I]WxH\f[R], \-\-geometry \f[I]WxH\f[R] +-g [\f[I]WxH\f[R] | -], --geometry [\f[I]WxH\f[R] | -] Sets the size of the X Window (or VNC window) that Medley runs in to be Width x Height. (Full X Windows geomtery specification with +X+Y is not currently supported). -If \-\-geometry is not specified but \-\-screensize is, then the window -size will be determined based on the \-\-screensize values and the -\-\-noscroll flag. -If neither \-\-geometry nor \-\-screensize is provided, then the window -size is set to 1440x900 if \-\-noscroll is set and 1462x922 if -\-\-noscroll is not set. +If a value of \[lq]-\[rq] is given, geometry is set to the default +value. +If --geometry is not specified but --screensize is, then the window size +will be determined based on the --screensize values and the --noscroll +flag. +If neither --geometry nor --screensize is provided, then the window size +is set to 1440x900 if --noscroll is set and 1462x922 if --noscroll is +not set. +(Also see note below under \f[I]CONFIG FILE\f[R] on the use of geometry +and screensize in config files.) .TP -.B \-s \f[I]WxH\f[R], \-\-screensize \f[I]WxH\f[R] +-s [\f[I]WxH\f[R] | -], --screensize [\f[I]WxH\f[R] | -] Sets the size of the virtual display as seen from Medley\[cq]s point of view. +If a value of \[lq]-\[rq] is given, screensize is set to the default +value. The Medley window is an unscaled viewport onto this virtual display. -If \-\-screensize is not specified but \-\-geometry is, then the virtual +If --screensize is not specified but --geometry is, then the virtual display size will be set so that the entire virtual display fits into the given window geometry. -If neither \-\-screensize nor \-\-geometry is provided, then the screen -size is set to 1440x900. +If neither --screensize nor --geometry is provided, then the screen size +is set to 1440x900. +(Also see note below under \f[I]CONFIG FILE\f[R] on the use of geometry +and screensize in config files.) .TP -.B \-t \f[I]STRING\f[R], \-\-title \f[I]STRING\f[R] +-ps [\f[I]N\f[R] | -], \[en]pixelscale [\f[I]N\f[R] | -]\ \ \ \ ** \f[B]Applicable only when display is SDL-based (e.g., on Windows/Cygwin)\f[R] ** +Sets the pixel scaling factor to \f[I]N\f[R]. +If value of \[lq]-\[rq] is given, the pixel scale factor is set to its +default of 1. +.TP +-t [\f[I]STRING\f[R] | -], --title [\f[I]STRING\f[R] | -] Use STRING as title of Medley window. -Ignored when when the \-\-vnc flag is set or when running on Windows -(Docker) installations. +If the value of \[lq]-\[rq] is given, sets the title to its default +value (\[lq]Medley Interlisp\[rq]). +Ignored when when the --vnc flag is set. .TP -.B \-d \f[I]:N\f[R], \-\-display \f[I]:N\f[R]\ \ \ \ ** \f[B]Not applicable to Windows (Docker) installations\f[R] ** +-d [\f[I]:N\f[R] | -], --display [\f[I]:N\f[R] | -] Use X display :N. -Defaults to the value of $DISPLAY. -This flag is ignored when the \-\-vnc flag is set as well as on Windows -(Docker) installations. +If value is \[lq]-\[rq], reset display to its default value. +Default value is the value of $DISPLAY. +On platforms that support X Windows as well as SDL, the value of -d +(\[en]display) should be set to \[lq]SDL\[rq] to select using SDL +instead of X Windows. +This flag is ignored on the Windows/Cygwin platform and when the --vnc +flag is set on Windows System for Linux. .TP -.B \-v, \-\-vnc\ \ \ \ ** \f[B]Applicable only to WSL installations\f[R] ** -Use a VNC window running on the Windows side instead of an X window. -The VNC window will folllow the Windows desktop scaling setting allowing +-v [+ | -] , --vnc [+ | -]\ \ \ \ ** \f[B]Applicable only to WSL installations\f[R] ** +If value is \[lq]+\[rq] or no value is given, then use a VNC window +running on the Windows side instead of an X window. +If value is \[lq]-\[rq], then do not use a VNC window, relying instead +on a standard X Window. +A VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well. This flag is always set for WSL1 installations. .TP -.B \-i [\f[I]ID_STRING\f[R] | \- | \-\-], \-\-id [\f[I]ID_STRING\f[R] | \- | \-\-] -Use ID_STRING as the id for this run of Medley, iunless ID_STRING is -\[lq]\-\[rq] or \[lq]\-\-\[rq]. -If ID_STRING is \[lq]\-\[rq], then use the basename of $MEDLEYDIR as the +-i [\f[I]ID_STRING\f[R] | - | --], --id [\f[I]ID_STRING\f[R] | - | --] +Use ID_STRING as the id for this run of Medley, unless ID_STRING is +\[lq]-\[rq], \[lq]--\[rq], or \[lq]---\[rq]. +If ID_STRING is \[lq]-\[rq], then reset the id to \[lq]default\[rq] +(e.g., if it was previously set in the config file). +If ID_STRING is \[lq]--\[rq], then use the basename of $MEDLEYDIR as the id. -If ID_STRING is \[lq]\-\-\[rq], then use the basename of the parent +If ID_STRING is \[lq]---\[rq], then use the basename of the parent directory of $MEDLEYDIR as the id. Only one instance of Medley with a given id can run at a time. The id is used to distinguish the virtual memory stores so that multiple instances of Medley can run simultaneously. Default id is \[lq]default\[rq]. .TP -.B \-m \f[I]N\f[R], \-\-mem \f[I]N\f[R] +-m [\f[I]N\f[R] | -], --mem [\f[I]N\f[R] | -] Set Medley to run in \f[I]N\f[R] MB of virtual memory. Defaults to 256MB. +If a value of \[lq]-\[rq] is given, resets to default value. .TP -.B \-p \f[I]FILE\f[R], \-\-vmem \f[I]FILE\f[R] +-p [\f[I]FILE\f[R] | -], --vmem [\f[I]FILE\f[R] | -] Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. -The \-\-id flag will not protect against vmem collisions when the -\-\-vmem flag is used. -Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where -XXX is the id of this Medley run (see \-\-id flag above). -See \-\-logindir below for setting of LOGINDIR. -On Windows (Docker) installations, \f[I]FILE\f[R] is specified in the -Medley file system, not the host Windows file system. +The --id flag will not protect against vmem collisions when the --vmem +flag is used. +If the value \[lq]-\[rq] is given, then resets the vmem file to the +default. +Default is to store the vmem in LOGINDIR/vmem/lisp_III.virtualmem, where +III is the id of this Medley run (see --id flag above). +See --logindir below for setting of LOGINDIR. .TP -.B \-r [\f[I]FILE\f[R] | \-], \-\-greet [\f[I]FILE\f[R] | \-] -Use FILE as the Medley greetfile, unless FILE is \[lq]\-\[rq] in which +-r [\f[I]FILE\f[R] | -], --greet [\f[I]FILE\f[R] | -] +Use FILE as the Medley greetfile, unless FILE is \[lq]-\[rq] in which case Medley will start up without using a greetfile. -The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR\-INIT, -except when the \-\-apps flag is used in which case it is -$MEDLEYDIR/greetfiles/APPS\-INIT. -On Windows (Docker) installations, \f[I]FILE\f[R] is specified in the +The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, +except when the --apps flag is used in which case it is +$MEDLEYDIR/greetfiles/APPS-INIT. +On Windows/Cygwin installations, \f[I]FILE\f[R] is specified in the Medley file system, not the host Windows file system. .TP -.B \-x [\f[I]DIR\f[R] | \-], \-\-logindir [\f[I]DIR\f[R] | \-]\ \ \ \ ** \f[B]On Linux and WSL installations\f[R] ** -Use DIR as LOGINDIR in Medley, unless DIR is \[lq]\-\[rq], in which case -use $MEDLEYDIR/logindir. +-x [\f[I]DIR\f[R] | - | \[en]], --logindir [\f[I]DIR\f[R] | - | \[en]] +Use DIR as LOGINDIR in Medley. +If the value is \[lq]\[en]\[rq], use $MEDLEYDIR/logindir as LOGINDIR. +If a value of \[lq]-\[rq] is given, then reset LOGINDIR to its default +value. DIR (or $MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to $HOME/il. -LOGINDIR is used by Medley as the working directory on start\-up and +LOGINDIR is used by Medley as the working directory on start-up and where it loads any \[lq]personal\[rq] initialization file from. +On Windows/Cygwin installations, \f[I]FILE\f[R] is specified in the +Medley file system, not the host Windows file system. .TP -.B \-x [\f[I]DIR\f[R] | \-], \-\-logindir [\f[I]DIR\f[R] | \-]\ \ \ \ ** \f[B]On Windows (Docker) installations\f[R] ** -Map DIR in the Windows host file system to /home/medley/il in the Medley -file system (in the Docker container). -LOGINDIR is always /home/medley/il from Medley\[cq]s standpoint. -The \[lq]\-\[rq] value is not valid in this case. +-nh \f[I]Host:Port:Mac:Debug\f[R], --nethub \f[I]Host:Port:Mac:Debug\f[R] +Set the parameters for using Nethub XNS networking. +\f[I]Host\f[R] is the full domain name of the nethub host. +\f[I]Port\f[R] is the port on \f[I]Host\f[R] that nethub is using. +\f[I]Mac\f[R] is the Mac address that this instance of Medley should use +when contacting the nethub host. +\f[I]Debug\f[R] is the level of nethub debug information that should be +printed on stdout (value is 0, 1, or 2). +A \f[I]Host\f[R] value is required and serves to turn nethub +functionality on. +\f[I]Port\f[R], \f[I]Mac\f[R] and \f[I]Debug\f[R] parameters are +optional and will default if left off. +Finally, if any of the parameters have a value of \[lq]-\[rq], any +previous setting (e.g., in a config file) for the parameter will be +reset to the default value - which in the case of \f[I]Host\f[R] is the +null string, turning nethub functionality off. .TP -.B \-u, \-\-update\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** -Before running Medley, do a pull to retrieve the latest interlisp/medley -docker image from Docker Hub. +-nf, -NF, \[en]nofork +No fork. +Relevant only to the Medley loadup workflow. .TP -.B \-b, \-\-background\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** -Run Medley in background rather than foreground. +-prog \f[I]EXE\f[R], \[en]maikoprog \f[I]EXE\f[R] +Use \f[I]EXE\f[R] as the basename of the Maiko executable. +Relevant only to the Medley loadup workflow. .TP -.B \-p \f[I]PORT\f[R], \-\-port \f[I]PORT\f[R]\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** -Use \f[I]PORT\f[R] as the port that VNC viewer uses to contact the VNC -server within the Docker container. -Default is 5900. -.TP -.B \-w [\f[I]DISTRO\f[R] | \-], \-\-wsl [\f[I]DISTRO\f[R] | \-]\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** -Run Medley in the context of the named WSL \f[I]DISTRO\f[R] instead of -within Docker. -If \f[I]DISTRO\f[R] is \[lq]\-\[rq], used the default WSL distro. -Equivalent to typing \[lq]wsl \-d \f[I]DISTRO\f[R] medley \&...\[rq] -into a Command or Powershell window. +\[en]maikodir \f[I]DIR\f[R] +Use \f[I]DIR\f[R] as the directory containing the Maiko emulator. +For testing purposes only. .SS Other Options .PP \ .TP -.B \f[I]SYSOUT_FILE\f[R] +\f[I]SYSOUT_FILE\f[R] The pathname of the file to use as a sysout for Medley to start from. -If SYSOUT_FILE is not provided and none of the flags (\-\-apps, -\-\-full, \-\-lisp) is used, then Medley will start from the saved -virtual memory file from the previous session with the same ID_STRING as -this run. +If SYSOUT_FILE is not provided and none of the flags (--apps, --full, +--lisp) is used, then Medley will start from the saved virtual memory +file from the previous session with the same ID_STRING as this run. If no such virtual memory file exists, then Medley will start from the -standard full.sysout (equivalent to specifying the \-\-full flag). +standard full.sysout (equivalent to specifying the --full flag). On Windows (Docker) installations, \f[I]SYSOUT_FILE\f[R] is specified in the Medley file system, not the host Windows file system. .TP -.B \f[I]PASS_ON_ARGS\f[R] -All arguments after the \[lq]\-\-\[rq] flag, are passed unaltered to lde -via run\-medley. -.SH FILES +\f[I]PASS_ON_ARGS\f[R] +All arguments after the \[lq]--\[rq] flag, are passed unaltered to the +Maiko emulator. +.SH CONFIG FILE +.PP +A config file can be used to \[lq]pre-specify\[rq] any of the above +command line arguments. +The config file consists of command line arguments (flags or flag-value +pairs), \f[I]one per line\f[R]. +These arguments are read from the config file and prepended to the +arguments actually given on the command line. +Since later arguments override earlier arguments, any argument actually +given on the command line will override a conflicting argument given in +the config file. +.PP +Unless specified using the -c (\[en]config) argument, the default config +file will be $MEDLEYDIR/.medley_config, if it exists, and +$HOME/.medley_config, otherwise. +.PP +Specifying, \[lq]-c -\[rq] or \[lq]\[en]config -\[rq] on the command +line will suppress the use of config files for the current run of +Medley. +.PP +\f[I]Note:\f[R] care must be taken when using -g (\[en]geometry) and/or +-s (\[en]screensize) arguments in config files. +If only one of these is specified, then the other is conputed. +But if both are specified, then the specified dimensions are used as +given. +Unexpected results can arise if one is specified in the config file but +the other is specified on the command line. +In this case, the two specified dimensions will be used as given. +It will not be the case, as might be expected, that the dimension given +in the config file will be overridden by a dimension computed from the +dimension given on the command line. +.SH OTHER FILES .TP -.B $HOME/il +$HOME/il Default Medley LOGINDIR .TP -.B $HOME/il/vmem/lisp.virtualmem +$HOME/il/vmem/lisp.virtualmem Default virtual memory file .TP -.B $HOME/il/INIT(.LCOM) +$HOME/il/INIT(.LCOM) Default personal init file .TP -.B $MEDLEYDIR/greetfiles/MEDLEYDIR\-INIT(.LCOM) +$MEDLEYDIR/greetfiles/MEDLEYDIR-INIT(.LCOM) Default Medley greetfile .SH BUGS .PP See GitHub Issues: .SH COPYRIGHT .PP -Copyright(c) 2023 by Interlisp.org +Copyright(c) 2023-2024 by Interlisp.org diff --git a/docs/man-page/medley.1.gz b/docs/man-page/medley.1.gz index a73df928a1f2be91c3feffc53428e32c33991601..f74b5a7995aaafbde4eab3ff8aa01477a4157963 100644 GIT binary patch literal 4418 zcmV-I5xwpoiwFowgg9mZ18rqwY-M>aF#yFoYj4}Qmf!g+h~i=qPi>{m&R$@O#R6%P zHU<(Wh%-Aa+M=K(+9o249zBwHus?p!gQO@~ZgVeicQFstB6;3#vdPz1^0cY#M%5-& zdA^e?UFcHPI+Kf?yj4YJQ+bm7mYgJSMe_BPNK__sk=$R(SJxNkR~MgO$yaaTKmK=K ztFo5YI?MG=PK#QXxv92rs#uF;eko_C*B2tWy%k@VU*3P)&_4L%-8cF5i{5;b6`rqT zv)zM1$LF7CH@EZYd>F(Rxy;q7l3)KVNfL>_;rsO4{PXLLC}b&}PwyDK zsiZ2TE*?#3i;XU7`KU^x7P*#{u2JX?2Z&xa73o22RI!tGDeJYCc3T@;R5H_5TABrJ z&^clch!6+vtnF6j`cdaHGo?;zTLvHwhbchdd9Dy5d{?zdZBZ-uOuMSBPR-J!lBFyW z;kKrYh{F_*_5tv#B}hX899iu)3!9r%~6a>1^9uN=&O4&4dZMGoPZLU&XNq~(q zT$x7=iz;24LZgVqS{EtEBbHriH`@k101j!`N{psVAjr>Ckj&@u0~#FbT7pyDiphEm zwzbyzR@|0AHDCrpm0XlYFJ;wiHmcPEn=2|>m8%Ag0pxC51PJdhga`T;^R<1VQ}9D> z)e4T=((UD~sr*7V-CFwp$jLW64_aNC)!?%Dz0$JxU9tMzsinyo7b&M~NC?-C#<@np z!|KM#r(j@bH?t4ZkFtg7jC8u}BLkRUzvO>@n|%FJ{t46q<^lw@-Gb#X9pD9sQpE&` zLj;i|mdNz7$#c;ONXyc0x;99daU&rI`>jA-iNG%j{{ZgNya8t;{2MT-T1Wnm$~&{0 zjV-S5XXMx7$<%8&6mX$?1ECpuq}`J1*Vg702&I;p1q_7^=w#&aYP$uWQtbAN#^g1K z#1yN*^AT!cIM$Ka*-~t|rz#4!07)>fRWf4vrUDoi+o@sze%N)}A@2uT$KsdX)nUi6tys|AKaEeJA=Qzqj#CXslZ9u-JNJ41-1@dcLJb|@Fiy5$L zmOHZ6ZD{}&SUDc^w(G<|G2}=mt7P1Yn%!C8+DJ|yjK@}uY!MCZelUx=fsC=y8%$*c z6M_UrdZ06G0~tLU+f;GbJ|br%g46~esk{McBJWUl6yHonxq$wh+ZCj9Q;x>cERit^ zT5uF)ggy!ZxK2se0|bpd`IN-E40OWEQ3Z;bERP8%E=aYok9w4di$5C!1af?Ev2iCk zJnkzr3b7UBcx0ACt<%@eMg2YX``qB@iFZwUDdK>qaCHE7ICwM>_ZXhJ-cdO?djYz5 z)TCHCx7|00AwQj62?j@oip3a*Xet*WX+5Db$TCoJ82EV;Y)1QWwMG#Oq_9vU zTX1GC566ZrA=E>i4^T5;BUighx}6JEQViDxH36>RDe==*5q=NEhZ_gMNh+@AeIw#M zuP#AG8cW{53pf!p1ADNRrmiA@!b6(3p2~tQq|@jTNhL7+dL-+ngaXAbmoaODASN*g zw|No(6bH}4(JtB%(Hu+*dDflq*+v>c$a_S)pnC31!gRF)tRw={^E)~1Fh!jWGKw)M zPED{!gP;LU4j~J*xK^=1$1ah$76%D`QoEpQOTY?SOdd^T&>XhZb~^v>Da{$6uj~JK zzU)T!m9`sQm%E{LDBNq;Sd!L;=ZdKuX^J`uCIP-%d{Ub_kM*MlGIV*@<}$K517fHbn+>4re;Yyld4wCj!yM zd=zn>3N>YQ$bzGzFSg-+WK+mENQ^QioAB2!>7U;~q}E_Xu>`-;PcO5zu1*eH+kHPK zyE+J5CskOwBTBS#5F9~(G z*@~RAo?BeAC6aK%p!>u>OS!{-sGPdSf=cK#+Eng-7^UE)iCVr>f z=VAD6>j*DX;BtO`HQ|uqiZ~$Jh0Ei!-3lZ;V&K30(waCCAdv!0giD3vJn9cxVxqd} zpaFM5X%DECJ*Zsx3JIXRbx9^P2={l>*~hMz)}{_(>95mxi9b?7Pg}#dCKN1F=es}g zJ}(Rg!_;k1HPNU^m8I^3LJFS*pgK2)-H=inHa?X zq_NK=3mkVrO)|lim7`}QtF>+N%ts5~iNZ)g4kPC~z`3DT{t6nKXQ#SHUxCZ9Q?L8|GiL?9{+M5NrqWgL z#us!qU0*9G5~-+`5>P%B)YEk&03k5r5w;T`B#Te6dkotUp~x)dg+3;#`);<{Ch7l;eW1) z&3>|poH{J}={Ou4o4k7MfMl*9$TxeN09EjTc6F0Rn*+F1Gg+@6_VK*Q; z7gu{&Bx1QiueF7{|G~?gIK9vao+}p+6i$CoR|>CWYO`^b8mzdU9z_XuiFVzXYCSY| ztbiOS>3#X+FPel$Uq$#mzRKV>RcI1_)Nf`%F0t;M@ot8yk;w$;*k8axA)1^bQd7jm zfxLc?gmsw-l+Xm?Lo0$qYhp~J+{OTTtnd}uiDc*BaWb7v@5e$vr+Qn*wy`&X z40KAO)1X?#F!a;g+c^Q|Y}+lnI+=4ka6#L)oTf98B#tVoz{c!OK;_M^d_aSZ605uGn>2J2E1vkK ztCqP{Sw)u-#Q9d2l`T~6J%r}#<}V)S@f(5CZvNlRt5`FFOW5}A7CNAJ*D8H?t{2UU z@X?fB*Xw5S<9(D+T_pmE0s2V3FJyn8F@#UExddQNsEG&=18elm11F-H-9Ye{agF21 zK!)5=q@#1xjfi9qFjXGzIH|hD4qS8~z;CIt%sr-{c@I6^*{hXYzXxU`DCW>hptSaP zbo<1%vhuk2v5{T+%^B|K+>~)^>N`uZ#V0b{4OVqV*P_8?-;Cv3s*O)Z*rD_!5Vn;# z@5hdkMm)NF)Z`O*mEgz_%ch`7J( zhk85L%bM>FK9~X@)%ly`sJQjO*6L9o2r^^3%nY~LK0o@pzUV%P8M$sGf*u}Hxn`j= zsdOkOE`j)NK=I&g(2xb*DT1OvX{#|w80m4k?g<&WXMe=EII|CKj8<5n@G`QD;-Cu3rH~B9<6!u$=YXl(m zvrd~DBk(^#T}ue&l1}<+=?DqU(b0xt_xR4coFfQIOa;qeO{ic^&57JL<B+F4?WAE6d6JGBWgeCCHE+>IqST5 zJK|c#Khhcterz=IY0G8R!!IeIR)3@+dfXg{kc7I=KtM`WxN-`Gey^YBCZ4C+z#&dC zhMt?~XJ`(qpVBA7kfrnFkysSB7tr$)H~2YuBcx;J$yzUu?2%a;2$OwM8#H_vKl#!ptVD- zL^QI@4U^A!n_M(t;>~jf1kxb`eZ6cXZ!xZ5AIU`fWc4hB3i>z zM`)rI+R)S1_%bTwabNlKa8ZN@uD8xD>0tspeY!u~c;e|Ay_#4#Y5ME15i);lOT2jv zZ!p~5*eEiX{xum!N9)IJ>|vGeM4aeqkEF=YsSA2e&2P3r2@8u;xl#`vYt11u8zcz_ zB&u{iuPV051gu9t!&a;w`3+!2!9kSAl6G`wpM zX{rZym}~l54fmH9cNCQ8lox!<8RkhY#rOuav#FgWMRTO~YHL5uc2DEf;wZT~ySW~P zL%tcMJ~TS>g2_rBRDVK4{J#JFBmWf+99Mlb^(9oe)2eE8^-lihx~{j?yW``P!OAxQ zX&p~{e?Q^a(B}VgDed<2-Sp$-JwZIP+g*vOK1xUOaF#ye4dvDt~691o{f+!Y;q?^cXwq0P0!vT41 zV<3r*D7~hLi-MMDn}{r`qGZR#efXOhk`g65ZSM989QJ`)8qV`KFRIbx1wXDUy%d#7 zM3!y%T;{SAl}!0`!^a{|b;6ILw=9~xV3A09#-iH`{^IKV?DG863;yCY{Ad4-D^XVb zN~W3I@L^ubGE=62Q~82}nA^I{xt`7VVpA++4gz(KGEzAcbyh_ziZA%}@zptt#$z^_ z-Jg735-<4U&1XKjm&?!GpbW$7VoMGkk3U_H#_=%T&ElTVGBG!N^0z38IR1v`!_V=j zc=X}+%b&x`b4y2W4kw399@&R*s9joi>sUq zzEg;Ja49YAV^FHsv7GfZT!d4j))mB6dwvT2%`;)W|}ZgXt+EQx}v1mDZU7 zgj77$AR*U{I36Hh6a`>QSolwCl~s@+DxW*EBDNPx`9#)Jj#w}060rh*T)L3vw(tNa zW^Fame(S}|dXcKobG(RzT`%Gj??s(wo7RNN-jH|9P-Dg+gL6WCc zt||pZ@%&LHuB~v)AMl_vWr`^gzy&EIc4pfwReo*Nq}G)4yVFZY(`cGoO>+(PTtjUb zmEdz|LRsrC;GBt#;g$k0S`uSu?AWMKQ)o>kJ}Ly2b>>b2SgTrOo`Y9D=sCVw-eRdo zeal)RSaRzjqy(Qq!`k9CQ-nWh1g{7=> z?C7W{wBC;@g`)k)FQl3;u<-l|`P(ou9K{0yH_eD(Q-n(WuXn$GLN{R*PwKLSXl5H` z>Y~skbk%)G;aS%PN8I{;3RMCrtk207Wyrx6Al3jzFTB4~Xh`J}+Ios5)pl>B?eSTO ztd_<{mv!QgotU)CrNUr#waj(7trS!ry;7-6pU@5=C9%Qr*Kgjudi>+nE3S5+4oFa= z*KdA5di>+)2xwTJhCC#z02pQ$FaqtK0gZl&3DgD5pwe%VF}Y8^eg-?W!b&y+pi0W# zUP8OU7ElE98h9VcFyIgd!als-g1Ey$*P*+S5MU+nwByLU`W--^Q;oJD|4~%|+cf2} z9T1&KUg#Dk0*yT?LNM>Zggx;TCW4?=t})%-46ok@ajjI9$*p(ngOS|+#@JaRh;6Ud z4(FgIc#|q@Q)ZFvDo+UZUMaAK-a|Rav7kZ{xtwQvXF7S1<$h;kH-YM@Rqx$(ptkpN z_-4ZGKQCW$+K`|a`#FHRi*CxyZjrWAzkEr?-!*}Jcir?s?rZJ^Ks z+J#;DYHA36kcikQM;i|soj{hhxsLUM9NdeI$ksH1Km<@KoPPbJuNA*1gbmNW1lhs= z1+VCTlS79`mHwELT;9B=yu#5eB{is$K?vF`JK(C$Gigk4Mj1x4GVr5G8H!Il_~Vn&Eoox5Ed7w53n z(3)opC^!qZa`cnH#kW#RX;BDoKtH(1$G44{z1)>4b(pIUke1RU}Lu{g69%zr^U}Opi_|*xj)HS19 zmX6;3esvN^E$sPb1#wlQk=(o>SmG}qk>1Gde71*2_pR$9M)b?tRM-*MrGn~!89Ut& z2REM4Fdwl~ysz=J6|5vVB`E0Zkz)`wq#E(1d{}E9hJ&^9Bvq+?IBs2$#dN|%r&5Gs zplQO+2Vj}w{ZnPdBv7MZTE>OnmuS|w#}^6&)AkC4^@$*bq!6Xc(fi>w;CX-#2Dm$Y zxx2fIocG|_0g5OkgQxxmO{F$RlnKUUzGr0D1~Jtu33F}io@aUvHBObmHt7o~u=9%8 zn)uyLchG}CcSBK~&15nX6&85ogM_N<9KdiW(;bG33yNd=8?w+;V@j6~+SaAX$dtD*T;Vka4J6`TTx6n1J zr9oZ(+%6H8MI7yIW#$}=?afgEkUqkTBL@qG0EOSmPY3y z^I1UmJ?fj?pDBpAd;O#kK69?V5(RgW3x`9(TYxk4+F$`|kGqry=kd;64-1L++$$@Z zyAKVZMAzYN>g)5}UP$RulD1OURKn_F=YF?M!Vl#V3UBuTUV(dS>&d!EMJ4+#`@X+u zcyF9`B4^lgeBbkshbdR^0&h=nV1Nx#$(3zPz(pFort5y%V5xPGTGG8f+U;C+QBMQK zr&jT)NFL^;uJiP-D1TEo7mVPimM1R-ExmZxg?&ug$J^t}cyx0cj4!nLcVGM!^{}jT zx%o^aK{OoVdV`k^pe-aVr8HqIvBeTzGf4gwybkUp`(W&h5pTPj`MSw6n6pP)xwtmj zQw0CJ$WScZAsn|-fn};*=z;co0l!>enqxJdeCW62u|#!j@bFvT0vsj zuQ$Bf6mvsE9HRdBi;mCga z?0;|Db&*dcp#boPiw>0|H_i(DkmWu|;DFXn^>+TSRT%sfaP|eo-|tW}%yA#;e9GJN zW5faT-{0DANc+C4xTS1+@@YT2h?PuPZ@h0>goS@8R|+O;m@kcKZeW{HJzQd$-(2l& z7TAev{4VbD5n^n9s2^)S3xywd_GAYbroEf@0~S(~r}m#eByD}C>CH+k7(oBaS!w6r z24Kf{@6&viwO_icpxd~9gXSF2_wGU%Oq&{7JkZ)LH%sw;U!e1GrSzYVFK9B3y#{^& zX-bf@$9Km*UAxExOH6ZkM_{)Y;Gnt}U7n7v_M3BlKB3X1d+a$gb)Q{-I484DKD@Vo zK>`=1_o{-%#)rn#(!Aq;UsP3L-VFwGKr%GEL@x)!UW*(kBK`+4I~|Qb-3;Gf+!DuA iU2IDHX0ey-^P^Wszv1xKoR4%lXa5H3&lcVmBLDzo`5g@a diff --git a/docs/man-page/medley.1.md b/docs/man-page/medley.1.md index 0f0ed85d..72a11539 100644 --- a/docs/man-page/medley.1.md +++ b/docs/man-page/medley.1.md @@ -41,6 +41,10 @@ Flags -z, \-\-man : Show the man page for medley +-c [*FILE* | -], \-\-config [*FILE* | -] +: Use *FILE* as the config file for this run of Medley. See information on *CONFIG FILE* below. If *FILE* is "-", +then suppress the use of a config file for this run of Medley. + -f, \-\-full : Start Medley from the standard "full" sysout. full.sysout includes a complete Interlisp and CommonLisp environment with a standard set of development tools. It does not include any of the applications built using Medley. @@ -57,88 +61,122 @@ applications including Notecards, Rooms and CLOS. It also includes pre-installe documentation. (See *SYSOUT_FILE* below for more information on starting sysouts.) --e, \-\-interlisp (relevent only when \-\-apps is specified) -: Make the initial Exec window within Medley be an Interlisp Exec. Default is to start in an XCL Exec. +-u, \-\-continue +: Nullify any prior setting of the sysout file (e.g., from the config file) - causing Medley to start from +the virtual memory file resulting from the previous invocation (with the same values for --id and --logindir), +if any. If there is no matching virtual memory file, Medley will start from the full.sysout (see -f/--full above). +Equivalent to "-y -". (See *SYSOUT FILE* section below.) --n, \-\-noscroll -: Ordinarily Medley displays scroll bars to enable the user to pan the Medley virtual display within the +-y [*SYSOUT_FILE* | -], \-\-sysout [*SYSOUT-FILE* | -] +: Start Medley from the specified *SYSOUT-FILE*. This is an alternative to specifying the *SYSOUT-FILE* +as the last argument on the command line (but before any *PASS_ON_ARGS*). It can be used to specify the +*SYSOUT-FILE* in the config file (see information on *CONFIG FILE* below). If *SYSOUT-FILE* is "-", then +any prior setting of the sysout file (e.g., from the config file) is nullified (see -u/--continue above). +(See *SYSOUT FILE* section below.) + +-e [+ | -], \-\-interlisp [+ | -] +: If value is "+" or no value, make the initial Exec window within Medley be an Interlisp Exec. +If value is "-", make the initial Exec window be the default XCL Exec. +This flag applies only when the --apps flag is used. + +-n [+ | -], \-\-noscroll [+ | -] +: Medley ordinarily displays scroll bars to enable the user to pan the Medley virtual display within the Medley window. This is true even when the entire virtual display fits within the window. Specifying -\-\-noscroll turns off the scroll bars. Note: If \-\-noscroll is specified and the virtual screen is larger +"-n +" (--noscroll +) turns off scroll bars. Specifying "-n -" (--scroll -) turns on scroll bars. +Specifying -n (--noscroll) with no value is equivalent to specifying "--noscroll +". Default +is scroll bars off. Note: If scroll bars are off and the virtual screen is larger than the window, there will be no way to pan to the non-visible parts of the virtual display. --g *WxH*, \-\-geometry *WxH* +-g [*WxH* | -], \-\-geometry [*WxH* | -] : Sets the size of the X Window (or VNC window) that Medley runs in to be Width x Height. (Full X Windows -geomtery specification with +X+Y is not currently supported). If \-\-geometry is not specified but \-\-screensize is, +geomtery specification with +X+Y is not currently supported). +If a value of "-" is given, geometry is set to the default value. +If \-\-geometry is not specified but \-\-screensize is, then the window size will be determined based on the \-\-screensize values and the \-\-noscroll flag. If neither \-\-geometry nor \-\-screensize is provided, then the window size is set to 1440x900 if \-\-noscroll is set and 1462x922 -if \-\-noscroll is not set. +if \-\-noscroll is not set. (Also see note below under *CONFIG FILE* on the use of geometry and screensize +in config files.) --s *WxH*, \-\-screensize *WxH* +-s [*WxH* | -], \-\-screensize [*WxH* | -] : Sets the size of the virtual display as seen from Medley's point of view. +If a value of "-" is given, screensize is set to the default value. The Medley window is an unscaled viewport onto this virtual display. If \-\-screensize is not specified but \-\-geometry is, then the virtual display size will be set so that the entire virtual display fits into the given window geometry. If neither \-\-screensize nor \-\-geometry is provided, then the screen size is set to 1440x900. +(Also see note below under *CONFIG FILE* on the use of geometry and screensize in config files.) --t *STRING*, \-\-title *STRING* -: Use STRING as title of Medley window. Ignored when when the \-\-vnc flag is set or when running on Windows (Docker) -installations. +-ps [*N* | -], --pixelscale [*N* | -]    \*\* **Applicable only when display is SDL-based (e.g., on Windows/Cygwin)** \*\* +: Sets the pixel scaling factor to *N*. If value of "-" is given, the pixel scale factor is set to its default of 1. --d *:N*, \-\-display *:N*    \*\* **Not applicable to Windows (Docker) installations** \*\* -~ Use X display :N. Defaults to the value of $DISPLAY. This flag is ignored when the \-\-vnc flag is set as -well as on Windows (Docker) installations. +-t [*STRING* | -], \-\-title [*STRING* | -] +: Use STRING as title of Medley window. If the value of "-" is given, sets the title to its default value ("Medley Interlisp"). +Ignored when when the \-\-vnc flag is set. --v, \-\-vnc    \*\* **Applicable only to WSL installations** \*\* -: Use a VNC window running on the Windows side instead of an X window. -The VNC window will folllow the Windows desktop scaling setting allowing +-d [*:N* | -], \-\-display [*:N* | -] +: Use X display :N. If value is "-", reset display to its default value. Default value is the value of $DISPLAY. +On platforms that support X Windows as well as SDL, the value of -d (--display) should +be set to "SDL" to select using SDL instead of X Windows. This flag is ignored on the Windows/Cygwin platform and when the \-\-vnc flag is +set on Windows System for Linux. + +-v [+ | -] , \-\-vnc [+ | -]    \*\* **Applicable only to WSL installations** \*\* +: If value is "+" or no value is given, then use a VNC window running on the Windows side instead of an X window. If value is "-", then do not +use a VNC window, relying instead on a standard X Window. +A VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well. This flag is always set for WSL1 installations. -i [*ID_STRING* | - | \-\-], \-\-id [*ID_STRING* | - | \-\-] -: Use ID_STRING as the id for this run of Medley, iunless ID_STRING is "-" or "\-\-". -If ID_STRING is "-", then use the basename of $MEDLEYDIR as the id. -If ID_STRING is "\-\-", then use the basename of the parent directory of $MEDLEYDIR as the id. +: Use ID_STRING as the id for this run of Medley, unless ID_STRING is "-", "\-\-", or "\-\-\-". +If ID_STRING is "-", then reset the id to "default" (e.g., if it was previously set in the +config file). If ID_STRING is "\-\-", then use the basename of $MEDLEYDIR as the id. +If ID_STRING is "\-\-\-", then use the basename of the parent directory of $MEDLEYDIR as the id. Only one instance of Medley with a given id can run at a time. The id is used to distinguish the virtual memory stores so that multiple instances of Medley can run simultaneously. Default id is "default". --m *N*, \-\-mem *N* -: Set Medley to run in *N* MB of virtual memory. Defaults to 256MB. +-m [*N* | -], \-\-mem [*N* | -] +: Set Medley to run in *N* MB of virtual memory. Defaults to 256MB. If a value of "-" is given, resets +to default value. --p *FILE*, \-\-vmem *FILE* +-p [*FILE* | -], \-\-vmem [*FILE* | -] : Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. The \-\-id flag will not protect against vmem collisions when the \-\-vmem flag is used. -Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this -Medley run (see \-\-id flag above). See \-\-logindir below for setting of LOGINDIR. On Windows (Docker) installations, *FILE* is specified in the Medley file system, not the host Windows file system. +If the value "-" is given, then resets the vmem file to the default. +Default is to store the vmem in LOGINDIR/vmem/lisp_III.virtualmem, where III is the id of this +Medley run (see \-\-id flag above). See \-\-logindir below for setting of LOGINDIR. -r \[*FILE* | -], \-\-greet \[*FILE* | -] : Use FILE as the Medley greetfile, unless FILE is "-" in which case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, except when the \-\-apps flag is used -in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. On Windows (Docker) installations, *FILE* is +in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. On Windows/Cygwin installations, *FILE* is specified in the Medley file system, not the host Windows file system. --x \[*DIR* | -], \-\-logindir \[*DIR* | -]    \*\* **On Linux and WSL installations** \*\* -: Use DIR as LOGINDIR in Medley, unless DIR is "-", in which case use -\$MEDLEYDIR/logindir. DIR (or \$MEDLEYDIR/logindir) must be writeable by the current user. +-x \[*DIR* | - | --], \-\-logindir \[*DIR* | - | --] +: Use DIR as LOGINDIR in Medley. If the value is "--", use +\$MEDLEYDIR/logindir as LOGINDIR. +If a value of "-" is given, then reset LOGINDIR to its default value. +DIR (or \$MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to \$HOME/il. LOGINDIR is used by Medley as the working directory on start-up -and where it loads any "personal" initialization file from. +and where it loads any "personal" initialization file from. On Windows/Cygwin installations, *FILE* is +specified in the Medley file system, not the host Windows file system. --x \[*DIR* | -], \-\-logindir \[*DIR* | -]    \*\* **On Windows (Docker) installations** \*\* -: Map DIR in the Windows host file system to /home/medley/il in the Medley -file system (in the Docker container). LOGINDIR is always /home/medley/il from Medley's standpoint. The "-" value is not valid in this case. +-nh *Host:Port:Mac:Debug*, \-\-nethub *Host:Port:Mac:Debug* +: Set the parameters for using Nethub XNS networking. *Host* is the full domain name of the nethub host. *Port* is the port on *Host* that nethub is using. +*Mac* is the Mac address that this instance of Medley should use when contacting the nethub host. *Debug* is the level of nethub debug information +that should be printed on stdout (value is 0, 1, or 2). A *Host* value is required and serves to turn nethub functionality on. *Port*, *Mac* and *Debug* +parameters are optional and will default if left off. Finally, if any of the parameters have a value of "-", any previous setting (e.g., in a config file) +for the parameter will be reset to the default value - which in the case of *Host* is the null string, turning nethub functionality off. --u, \-\-update    \*\* **Windows (Docker) installations only** \*\* -: Before running Medley, do a pull to retrieve the latest interlisp/medley docker image from Docker Hub. +-nf, -NF, --nofork +: No fork. Relevant only to the Medley loadup workflow. --b, \-\-background    \*\* **Windows (Docker) installations only** \*\* -: Run Medley in background rather than foreground. +-prog *EXE*, --maikoprog *EXE* +: Use *EXE* as the basename of the Maiko executable. Relevant only to the Medley loadup workflow. --p *PORT*, \-\-port *PORT*    \*\* **Windows (Docker) installations only** \*\* -: Use *PORT* as the port that VNC viewer uses to contact the VNC server within the Docker container. Default is 5900. - --w \[*DISTRO* | -], \-\-wsl \[*DISTRO* | -]    \*\* **Windows (Docker) installations only** \*\* -: Run Medley in the context of the named WSL *DISTRO* instead of within Docker. If *DISTRO* is "-", used the default WSL distro. Equivalent to typing "wsl -d *DISTRO* medley ..." into a Command or Powershell window. +--maikodir *DIR* +: Use *DIR* as the directory containing the Maiko emulator. For testing purposes only. Other Options @@ -154,11 +192,33 @@ If no such virtual memory file exists, then Medley will start from the standard specified in the Medley file system, not the host Windows file system. *PASS_ON_ARGS* -: All arguments after the "\-\-" flag, are passed unaltered to lde via run-medley. +: All arguments after the "\-\-" flag, are passed unaltered to the Maiko emulator. -FILES -===== +CONFIG FILE +=========== +A config file can be used to "pre-specify" any of the above command line arguments. +The config file consists of command line arguments (flags or flag-value pairs), *one per line*. +These arguments are read from the config file and prepended to the arguments actually given on +the command line. Since later arguments override earlier arguments, any argument actually given +on the command line will override a conflicting argument given in the config file. + +Unless specified using the -c (--config) argument, the default config file will be $MEDLEYDIR/.medley_config, +if it exists, and $HOME/.medley_config, otherwise. + +Specifying, "-c -" or "--config -" on the command line will suppress the use of config files for the +current run of Medley. + +*Note:* care must be taken when using -g (--geometry) and/or -s (--screensize) arguments in config files. +If only one of these is specified, then the other is conputed. But if both are specified, then the specified +dimensions are used as given. Unexpected results can arise if one is specified in the config file +but the other is specified on the command line. In this case, the two specified dimensions will be used as given. +It will not be the case, as might be expected, that the dimension given in the config file will be overridden +by a dimension computed from the dimension given on the command line. + + +OTHER FILES +=========== \$HOME/il : Default Medley LOGINDIR @@ -181,4 +241,4 @@ See GitHub Issues: COPYRIGHT ========= -Copyright(c) 2023 by Interlisp.org +Copyright(c) 2023-2024 by Interlisp.org diff --git a/run-medley b/run-medley index 03c728d3..69e098fd 100755 --- a/run-medley +++ b/run-medley @@ -18,6 +18,9 @@ # LDEDESTSYSOUT name for destination of SaveVM/LOGOUT # MEDLEYDIR used by init file to set other path variables +#for x in "$@"; do echo $x; done +#exit + inferred_medleydir=false if [ -z "$MEDLEYDIR" ] ; then diff --git a/scripts/loadup-all.sh b/scripts/loadup-all.sh index 5cc8f005..cc54a941 100755 --- a/scripts/loadup-all.sh +++ b/scripts/loadup-all.sh @@ -1,27 +1,43 @@ #!/bin/sh +# shellcheck disable=SC2181 -if [ ! -x run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh -if [ "$1" = "-apps" ]; then +# look thru args looking to see if -apps, --apps, or -a was specified in args +apps=true +j=1 +jmax=$# +while [ "$j" -le "$jmax" ] +do + if [ "$(eval "printf %s \${${j}}")" = "-a" ] || \ + [ "$(eval "printf %s \${${j}}")" = "-apps" ] || \ + [ "$(eval "printf %s \${${j}}")" = "--apps" ] + then apps="./scripts/loadup-apps-from-full.sh" -else - apps="true" -fi + break + fi +done +# Do loadup components ./scripts/loadup-init.sh && \ ./scripts/loadup-mid-from-init.sh && \ ./scripts/loadup-lisp-from-mid.sh && \ ./scripts/loadup-full-from-lisp.sh && \ ${apps} && \ ./scripts/loadup-aux.sh && \ - ./scripts/copy-all.sh $1 + ./scripts/copy-all.sh "$1" -if [ $? -eq 0 ]; +if [ $? -eq 0 ] then echo "+++++ loadup-all.sh: SUCCESS +++++" else diff --git a/scripts/loadup-apps-from-full.sh b/scripts/loadup-apps-from-full.sh index e10ef35e..38a2a59c 100755 --- a/scripts/loadup-apps-from-full.sh +++ b/scripts/loadup-apps-from-full.sh @@ -1,29 +1,38 @@ #!/bin/sh -if [ ! -x run-medley ] ; then - echo must run from MEDLEYDIR ; - exit 1 ; +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." + exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start -export ROOMSDIR=${MEDLEYDIR}/rooms -export CLOSDIR=${MEDLEYDIR}/clos +export ROOMSDIR="${MEDLEYDIR}/rooms" +export CLOSDIR="${MEDLEYDIR}/clos" -export NOTECARDSDIR=${MEDLEYDIR}/notecards -if [ ! -e ${NOTECARDSDIR} ]; then - NOTECARDSDIR=$(cd ${MEDLEYDIR}/../ && pwd)/notecards - if [ ! -e ${NOTECARDSDIR} ]; then - NOTECARDSDIR=$(cd ${MEDLEYDIR}/../../ && pwd)/notecards - if [ ! -e ${NOTECARDSDIR} ]; then +export NOTECARDSDIR="${MEDLEYDIR}/notecards" +if [ ! -e "${NOTECARDSDIR}" ] +then + NOTECARDSDIR=$(cd "${MEDLEYDIR}/../" && pwd)/notecards + if [ ! -e "${NOTECARDSDIR}" ] + then + NOTECARDSDIR=$(cd "${MEDLEYDIR}/../../" && pwd)/notecards + if [ ! -e "${NOTECARDSDIR}" ] + then NOTECARDSDIR="" fi fi fi -if [ -z "${NOTECARDSDIR}" ]; then +if [ -z "${NOTECARDSDIR}" ] +then echo "Error: Cannot find the Notecards directory" echo "It should be located at ${MEDLEYDIR}/../notecards or" echo "${MEDLEYDIR}/../../notecards. But its not." @@ -62,6 +71,6 @@ SHH " EOF -./run-medley ${scr} -loadup "${cmfile}" "${LOADUP_WORKDIR}/full.sysout" +run_medley "${LOADUP_WORKDIR}/full.sysout" loadup_finish "apps.sysout" "apps.*" diff --git a/scripts/loadup-aux.sh b/scripts/loadup-aux.sh index 598f6955..625394e6 100755 --- a/scripts/loadup-aux.sh +++ b/scripts/loadup-aux.sh @@ -1,10 +1,15 @@ #!/bin/sh -if [ ! -f run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start @@ -26,6 +31,6 @@ cat >"${cmfile}" <<"EOF" " EOF -./run-medley ${scr} -loadup "${cmfile}" "${LOADUP_WORKDIR}"/full.sysout +run_medley "${LOADUP_WORKDIR}/full.sysout" loadup_finish "whereis.hash" "whereis.hash" "exports.all" diff --git a/scripts/loadup-db-from-full.sh b/scripts/loadup-db-from-full.sh index 6517fb3e..16fd5206 100755 --- a/scripts/loadup-db-from-full.sh +++ b/scripts/loadup-db-from-full.sh @@ -1,10 +1,15 @@ #!/bin/sh -if [ ! -x run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start @@ -35,7 +40,7 @@ cat >"${cmfile}" <<"EOF" " EOF -./run-medley ${scr} -loadup "${cmfile}" "${SYSOUT}" +run_medley "${SYSOUT}" loadup_finish "fuller.database" "fuller*" diff --git a/scripts/loadup-db.sh b/scripts/loadup-db.sh index d0f89f7a..1ed597c4 100755 --- a/scripts/loadup-db.sh +++ b/scripts/loadup-db.sh @@ -1,10 +1,16 @@ #!/bin/sh +# shellcheck disable=SC2181 -if [ ! -x run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh ./scripts/loadup-db-from-full.sh && ./scripts/copy-db.sh diff --git a/scripts/loadup-full-from-lisp.sh b/scripts/loadup-full-from-lisp.sh index 638e839b..c190b96e 100755 --- a/scripts/loadup-full-from-lisp.sh +++ b/scripts/loadup-full-from-lisp.sh @@ -1,10 +1,15 @@ #!/bin/sh -if [ ! -x run-medley ] ; then - echo must run from MEDLEYDIR ; - exit 1 ; +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." + exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start @@ -27,7 +32,7 @@ SHH " EOF -./run-medley ${scr} -loadup "${cmfile}" "${LOADUP_WORKDIR}/lisp.sysout" +run_medley "${LOADUP_WORKDIR}/lisp.sysout" loadup_finish "full.sysout" "full.*" diff --git a/scripts/loadup-full.sh b/scripts/loadup-full.sh index a5938705..385d9804 100755 --- a/scripts/loadup-full.sh +++ b/scripts/loadup-full.sh @@ -1,10 +1,16 @@ #!/bin/sh +# shellcheck disable=SC2181 -if [ ! -x run-medley ] ; then - echo must run from MEDLEYDIR ; - exit 1 ; +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." + exit 1 fi +# shellcheck source=./loadup-setup.sh . ./scripts/loadup-setup.sh ./scripts/loadup-init.sh && \ diff --git a/scripts/loadup-init.sh b/scripts/loadup-init.sh index 5db49820..e61403fb 100755 --- a/scripts/loadup-init.sh +++ b/scripts/loadup-init.sh @@ -1,10 +1,15 @@ #!/bin/sh -if [ ! -f run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start @@ -40,6 +45,6 @@ cat >"${cmfile}" <<"EOF" STOP EOF -./run-medley $scr -loadup "${cmfile}" "${LOADUP_SOURCEDIR}"/starter.sysout +run_medley "${LOADUP_SOURCEDIR}/starter.sysout" loadup_finish "init.dlinit" "init.*" "RDSYS*" "I-NEW*" diff --git a/scripts/loadup-lisp-from-mid.sh b/scripts/loadup-lisp-from-mid.sh index 6888da26..21d33456 100755 --- a/scripts/loadup-lisp-from-mid.sh +++ b/scripts/loadup-lisp-from-mid.sh @@ -1,10 +1,15 @@ #!/bin/sh -if [ ! -f run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start @@ -29,6 +34,6 @@ SHH " EOF -./run-medley ${scr} -loadup "${cmfile}" "${LOADUP_WORKDIR}/init-mid.sysout" +run_medley "${LOADUP_WORKDIR}/init-mid.sysout" loadup_finish "lisp.sysout" "lisp.*" diff --git a/scripts/loadup-mid-from-init.sh b/scripts/loadup-mid-from-init.sh index 7efc13e4..bcb2075c 100755 --- a/scripts/loadup-mid-from-init.sh +++ b/scripts/loadup-mid-from-init.sh @@ -1,10 +1,15 @@ #!/bin/sh -if [ ! -x run-medley ] ; then - echo run from MEDLEYDIR +if [ ! -h ./medley ] || [ ! -d ./lispusers ] +then + echo "*** ERROR ***" + echo "You must run $(basename "$0") while the cwd is a Medley top-level directory." + echo "The cwd ($(pwd)) is not a Medley top-level directory." + echo "Exiting." exit 1 fi +# shellcheck source=./loadup-setup.sh . scripts/loadup-setup.sh loadup_start @@ -18,9 +23,8 @@ cat >"${cmfile}" <<"EOF" " EOF -./run-medley -prog "ldeinit" \ - -NF \ - -loadup "${cmfile}" ${scr} -vmem "${LOADUP_WORKDIR}/init-mid.sysout" \ - "${LOADUP_WORKDIR}/init.dlinit" +run_medley "${LOADUP_WORKDIR}/init.dlinit" -NF -prog ldeinit --vmem "${LOADUP_WORKDIR}/init-mid.sysout" + +echo " " loadup_finish "init-mid.sysout" "init-mid.sysout" diff --git a/scripts/loadup-setup.sh b/scripts/loadup-setup.sh index 7f197685..f055f198 100644 --- a/scripts/loadup-setup.sh +++ b/scripts/loadup-setup.sh @@ -1,19 +1,31 @@ +#!sh +# shellcheck shell=sh -export MEDLEYDIR=`pwd` +MEDLEYDIR="$(pwd)" +export MEDLEYDIR -if [ -z "${LOADUP_WORKDIR}" ]; +if [ -z "${LOADUP_WORKDIR}" ] then - export LOADUP_WORKDIR=/tmp/loadups-$$ + LOADUP_WORKDIR=/tmp/loadups-$$ + export LOADUP_WORKDIR fi -if [ -z "${LOADUP_SOURCEDIR}" ]; +if [ -z "${LOADUP_SOURCEDIR}" ] then - export LOADUP_SOURCEDIR="${MEDLEYDIR}"/internal/loadups + LOADUP_SOURCEDIR="${MEDLEYDIR}/internal/loadups" + export LOADUP_SOURCEDIR fi -if [ -z "${LOADUP_OUTDIR}" ]; +if [ -z "${LOADUP_OUTDIR}" ] then - export LOADUP_OUTDIR="${MEDLEYDIR}"/loadups + LOADUP_OUTDIR="${MEDLEYDIR}/loadups" + export LOADUP_OUTDIR +fi + +if [ -z "${LOADUP_LOGINDIR}" ] +then + LOADUP_LOGINDIR="${LOADUP_WORKDIR}/logindir" + export LOADUP_LOGINDIR fi if [ ! -d "${LOADUP_OUTDIR}" ]; @@ -22,7 +34,8 @@ then then mkdir -p "${LOADUP_OUTDIR}" else - "Error: ${LOADUP_OUTDIR} exists but is not a directory. Exiting." + echo "Error: ${LOADUP_OUTDIR} exists but is not a directory. Exiting." + exit 1 fi fi @@ -32,18 +45,37 @@ then then mkdir -p "${LOADUP_WORKDIR}" else - "Error: ${LOADUP_WORKDIR} exists but is not a directory. Exiting." + echo "Error: ${LOADUP_WORKDIR} exists but is not a directory. Exiting." + exit 1 fi fi + + scr="-sc 1024x768 -g 1042x790" +geometry=1024x768 touch "${LOADUP_WORKDIR}"/loadup.timestamp script_name=$(basename "$0" ".sh") cmfile="${LOADUP_WORKDIR}/${script_name}.cm" +# look thru args looking to see if oldschool was specified in args +j=1 +jmax=$# +while [ "$j" -le "$jmax" ] +do + if [ "$(eval "printf %s \${${j}}")" = "-os" ] || [ "$(eval "printf %s \${${j}}")" = "--oldschool" ] + then + LOADUP_OLDSCHOOL=true + export LOADUP_OLDSCHOOL + break + else + j=$(( j + 1 )) + fi +done + ###################################################################### @@ -65,9 +97,12 @@ loadup_start () { } loadup_finish () { - local exit_code rm -f "${cmfile}" - if [ "${LOADUP_WORKDIR}"/loadup.timestamp -nt "${LOADUP_WORKDIR}/${1}" ]; +# 2024-05-05 FGH +# Can't use exit code for now since on MacOS exit codes appear to be inverted +# Will restore once MacOS exit code are figured out +# if [ "${exit_code}" -ne 0 ] || [ ! -f "${LOADUP_WORKDIR}/$1" ] + if [ ! -f "${LOADUP_WORKDIR}/$1" ] then echo "----- FAILURE -----" exit_code=1 @@ -76,17 +111,19 @@ loadup_finish () { exit_code=0 fi echo "..... files created ....." + if [ -f "${LOADUP_WORKDIR}/$1" ] + then shift; - for f in ${*}; + for f in "$@" do + # shellcheck disable=SC2045,SC2086 for ff in $(ls -1 "${LOADUP_WORKDIR}"/$f); do - if [ "${ff}" -nt "${LOADUP_WORKDIR}"/loadup.timestamp ]; - then - ls -l ${ff} 2>/dev/null | grep -v "^.*~[0-9]\+~$" - fi + # shellcheck disable=SC2010 + ls -l "${ff}" 2>/dev/null | grep -v "^.*~[0-9]\+~$" done done + fi if [ "${TMP_PRE_EXISTS}" = "false" ]; then rm -rf "${MEDLEYDIR}/tmp" @@ -101,6 +138,26 @@ loadup_finish () { exit ${exit_code} } +run_medley () { + if [ ! "${LOADUP_OLDSCHOOL}" = true ] + then + ./medley --config - \ + --id loadup_+ \ + --geometry "${geometry}" \ + --noscroll \ + --logindir "${LOADUP_LOGINDIR}" \ + --greet "${cmfile}" \ + --sysout "$1" \ + "$2" "$3" "$4" "$5" "$6" "$7" ; + exit_code=$? + else + # shellcheck disable=SC2086 + ./run-medley ${scr} $2 $3 $4 $5 $6 $7 -loadup "${cmfile}" "$1" + exit_code=$? + fi + +} + ###################################################################### diff --git a/scripts/medley/README b/scripts/medley/README new file mode 100644 index 00000000..97401610 --- /dev/null +++ b/scripts/medley/README @@ -0,0 +1,6 @@ +Note that medley.sh is just a symbolic link to medley.command (to accomodate MacOS). + +medley.command should not be edited directly. It is compiled from all the of the +medley_*.sh components. The script compile.sh does this compile (with help from +the inline.sh script). + diff --git a/scripts/medley/compile.sh b/scripts/medley/compile.sh new file mode 100755 index 00000000..3066a48f --- /dev/null +++ b/scripts/medley/compile.sh @@ -0,0 +1,5 @@ +#!/bin/sh +mv medley.command medley.command~ +./inline.sh --in-file medley_main.sh --out-file medley.command +chmod +x medley.command + diff --git a/scripts/medley/inline.sh b/scripts/medley/inline.sh new file mode 100755 index 00000000..50e51d53 --- /dev/null +++ b/scripts/medley/inline.sh @@ -0,0 +1,460 @@ +#!/usr/bin/env sh +# MIT License +# +# Copyright (c) 2022-2022 Carlo Corradini +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Inspired by https://gist.github.com/joehillen/30f08738c1c3c0ca3e4c754ad33ad2ff + +# Fail on error +set -o errexit +# Disable wildcard character expansion +set -o noglob + +# PID shell +SELF_PID=$$ + +# ================ +# LOGGER +# ================ +# Fatal log level. Cause exit failure +LOG_LEVEL_FATAL=100 +# Warning log level +LOG_LEVEL_WARN=200 +# Informational log level +LOG_LEVEL_INFO=300 +# Debug log level +LOG_LEVEL_DEBUG=400 +# Silent log level +LOG_LEVEL_SILENT=500 +# Log level +LOG_LEVEL=$LOG_LEVEL_INFO +# Log color flag +LOG_COLOR_ENABLE=true + +# Convert log level to equivalent name +# @param $1 Log level +to_log_level_name() { + _log_level=${1:-LOG_LEVEL} + _log_level_name= + + case $_log_level in + "$LOG_LEVEL_FATAL") _log_level_name=fatal ;; + "$LOG_LEVEL_WARN") _log_level_name=warn ;; + "$LOG_LEVEL_INFO") _log_level_name=info ;; + "$LOG_LEVEL_DEBUG") _log_level_name=debug ;; + "$LOG_LEVEL_SILENT") _log_level_name=silent ;; + *) FATAL "Unknown log level '$_log_level'" ;; + esac + + printf "%s\n" "$_log_level_name" +} + +# Print log message +# @param $1 Log level +# @param $2 Message +_log_print_message() { + _log_level=${1:-LOG_LEVEL_FATAL} + shift + _log_level_name= + _log_message=${*:-} + _log_prefix= + _log_suffix="\033[0m" + + # Check log level + if [ "$LOG_LEVEL" -eq "$LOG_LEVEL_SILENT" ] || [ "$_log_level" -gt "$LOG_LEVEL" ]; then + return 0 + fi + + case $_log_level in + "$LOG_LEVEL_FATAL") + _log_level_name=FATAL + _log_prefix="\033[41;37m" + ;; + "$LOG_LEVEL_WARN") + _log_level_name=WARN + _log_prefix="\033[1;33m" + ;; + "$LOG_LEVEL_INFO") + _log_level_name=INFO + _log_prefix="\033[37m" + ;; + "$LOG_LEVEL_DEBUG") + _log_level_name=DEBUG + _log_prefix="\033[1;34m" + ;; + esac + + # Check color flag + if [ "$LOG_COLOR_ENABLE" = false ]; then + _log_prefix= + _log_suffix= + fi + + # Log + printf '%b[%-5s] %b%b\n' "$_log_prefix" "$_log_level_name" "$_log_message" "$_log_suffix" +} + +# Fatal log message +# @param $1 Message +FATAL() { + _log_print_message "$LOG_LEVEL_FATAL" "$1" >&2 + exit 1 +} +# Warning log message +# @param $1 Message +WARN() { _log_print_message "$LOG_LEVEL_WARN" "$1" >&2; } +# Informational log message +# @param $1 Message +INFO() { _log_print_message "$LOG_LEVEL_INFO" "$1" >&2; } +# Debug log message +# @param $1 Message +DEBUG() { _log_print_message "$LOG_LEVEL_DEBUG" "$1" >&2; } + +# ================ +# FUNCTIONS +# ================ +# Show help message +show_help() { + cat << EOF +Usage: $(basename "$0") --in-file [--disable-color] [--help] [--log-level ] [--out-file ] [--overwrite] + +reCluster bundle script. + +Options: + --disable-color Disable color + + --help Show this help message and exit + + --in-file Input file + Values: + Any valid file + + --log-level Logger level + Default: $(to_log_level_name "$LOG_LEVEL") + Values: + fatal Fatal level + warn Warning level + info Informational level + debug Debug level + silent Silent level + + --out-file Output file + Default: [IN_FILE_NAME].inlined[IN_FILE_EXTENSION] + Values: + Any valid file + + --overwrite Overwrite input file +EOF +} + +# Assert command is installed +# @param $1 Command name +assert_cmd() { + command -v "$1" > /dev/null 2>&1 || FATAL "Command '$1' not found" + DEBUG "Command '$1' found at '$(command -v "$1")'" +} + +# ================ +# CACHE +# ================ +# Cache +CACHE= + +# Add file path to cache +# @param $1 File path +cache_add() { + if [ -z "$CACHE" ]; then + CACHE=$(printf '%s\n' "$1") + else + CACHE=$(printf '%s\n%s\n' "$CACHE" "$1") + fi +} + +# Check cache has file path +# @param $1 File path +cache_has() { + while read -r _entry; do + if [ "$_entry" = "$1" ]; then + return 0 + fi + done << EOF +$CACHE +EOF + + return 1 +} + +# Inline sources ('source' or '.') of given script file +# @param $1 Script file path +inline_sources() { + _file=$1 + _file_dir=$(dirname "$_file") + _regex='^([[:space:]]*)(source|\.)[[:space:]]+(.+)' + _regex_inline_skip='^[[:space:]]*#[[:space:]]*inline[[:space:]]+skip.*' + _regex_shellcheck='^[[:space:]]*#[[:space:]]*shellcheck[[:space:]]+source=(.+)' + _inline_skip=false + _source_file_shellcheck= + + [ -f "$_file" ] || FATAL "File '$_file' does not exists" + INFO "Reading file '$_file'" + + # Add to cache + cache_add "$_file" + + # Read + while IFS='' read -r _line; do + DEBUG "Analyzing line '$_line'" + + if printf "%s\n" "$_line" | grep -q -E "$_regex_inline_skip"; then + # # inline skip + _inline_skip=true + DEBUG "Inline skip '$_line'" + + # Print line + printf '%s\n' "$_line" + elif printf "%s\n" "$_line" | grep -q -E "$_regex_shellcheck"; then + # # shellcheck source=... + DEBUG "ShellCheck source '$_line'" + + # Source + _source_file_shellcheck=$(printf "%s\n" "$_line" | sed -n -r "s/$_regex_shellcheck/\1/p") + # Print line + printf '%s\n' "$_line" + elif printf "%s\n" "$_line" | grep -q -E "$_regex"; then + # source ... + # . ... + DEBUG "Source '$_line'" + + # Source + _source_file=$(printf "%s\n" "$_line" | sed -n -r "s/$_regex/\3/p" | sed -e 's/^"//' -e 's/"$//') + + # Check skip + [ "$_inline_skip" = false ] || { + # Skip + WARN "Skipping source '$_line'" + # Reset inline skip + _inline_skip=false + # Reset shellcheck + _source_file_shellcheck= + # Print line + printf '%s\n' "$_line" + continue + } + + # Resolve source path + _path= + if printf "%s\n" "$_source_file" | grep -q -E -v '.*\/.*'; then + # Search $PATH + DEBUG "Searching '\$PATH'" + + _path=$(command -v "$_source_file" || :) + fi + if [ -z "$_path" ]; then + # Resolve links, relative paths, ~, quotes, and escapes + DEBUG "Path is undefined, continue searching" + + _path=$_source_file + if printf "%s\n" "$_path" | grep -q -E -v '^\/|^\$'; then + # Path does not start with '/' or '$' symbol, preprend directory + _path="$_file_dir/$_path" + fi + + # Canonicalize + _path=$(eval readlink -f "$_path" || :) + DEBUG "Path candidate '$_path'" + + if [ ! -f "$_path" ] && [ -n "$_source_file_shellcheck" ]; then + # File does not exists, try shellcheck + DEBUG "Path '$_path' is invalid, searching ShellCheck" + + _path=$_source_file_shellcheck + if printf "%s\n" "$_path" | grep -q -E -v '^\/'; then + # Path does not start with '/' symbol, preprend directory + _path="$_file_dir/$_path" + fi + + # Canonicalize + _path=$(readlink -f "$_path" || :) + DEBUG "Path candidate '$_path'" + # Reset shellcheck + _source_file_shellcheck= + fi + fi + + # Check path + [ -f "$_path" ] || FATAL "Unable to resolve source file path '$_source_file'" + DEBUG "Source '$_source_file' resolved to '$_path'" + + # Comment source + printf '# %s\n' "$_line" + + # Check if already sourced + ! cache_has "$_path" || { + WARN "Recursion detected, source '$_source_file' of '$_file'" + kill $SELF_PID + wait $SELF_PID + } + + # Inline source and remove shebang + inline_sources "$_path" | sed '/^#!.*/d' + else + # Reset inline skip + _inline_skip=false + # Reset shellcheck + _source_file_shellcheck= + # Print line + printf '%s\n' "$_line" + fi + done < "$_file" +} + +################################################################################################################################ + +# Parse command line arguments +# @param $@ Arguments +parse_args() { + # Assert argument has a value + # @param $1 Argument name + # @param $2 Argument value + parse_args_assert_value() { + [ -n "$2" ] || FATAL "Argument '$1' requires a non-empty value" + } + + while [ $# -gt 0 ]; do + case $1 in + --disable-color) + # Disable color + LOG_COLOR_ENABLE=false + shift + ;; + --help) + # Display help message and exit + show_help + exit 0 + ;; + --in-file) + # Input file + parse_args_assert_value "$@" + + IN_FILE=$2 + shift + shift + ;; + --log-level) + # Log level + parse_args_assert_value "$@" + + case $2 in + fatal) LOG_LEVEL=$LOG_LEVEL_FATAL ;; + warn) LOG_LEVEL=$LOG_LEVEL_WARN ;; + info) LOG_LEVEL=$LOG_LEVEL_INFO ;; + debug) LOG_LEVEL=$LOG_LEVEL_DEBUG ;; + silent) LOG_LEVEL=$LOG_LEVEL_SILENT ;; + *) FATAL "Value '$2' of argument '$1' is invalid" ;; + esac + shift + shift + ;; + --out-file) + # Output file + parse_args_assert_value "$@" + + OUT_FILE=$2 + shift + shift + ;; + --overwrite) + # Overwrite + OVERWRITE=true + shift + ;; + -*) + # Unknown argument + WARN "Unknown argument '$1' is ignored" + shift + ;; + *) + # No argument + WARN "Skipping argument '$1'" + shift + ;; + esac + done + + # Determine output file + if [ "$OVERWRITE" = true ]; then + # Input file + OUT_FILE=$IN_FILE + elif [ -n "$IN_FILE" ] && [ -z "$OUT_FILE" ]; then + # Input file 'inlined' + _in_file_basename=$(basename -- "$IN_FILE") + _in_file_name="${_in_file_basename%.*}" + _in_file_extension= + case $_in_file_basename in + *.*) _in_file_extension=".${_in_file_basename##*.}" ;; + esac + + OUT_FILE="$_in_file_name.inlined$_in_file_extension" + fi +} + +# Verify system +verify_system() { + assert_cmd grep + assert_cmd sed + + [ -n "$IN_FILE" ] || FATAL "Input file required" + [ -f "$IN_FILE" ] || FATAL "Input file '$IN_FILE' does not exists" + if [ "$OVERWRITE" = false ] && [ -f "$OUT_FILE" ]; then FATAL "Output file '$OUT_FILE' already exists"; fi +} + +# Inline input file +inline() { + INFO "Inlining file '$IN_FILE'" + _inlined=$(inline_sources "$(readlink -f "$IN_FILE")") || FATAL "Error inlining file '$IN_FILE'" + + INFO "Saving file '$OUT_FILE'" + printf '%s\n' "$_inlined" > "$OUT_FILE" +} + +# ================ +# CONFIGURATION +# ================ +# Input file +IN_FILE= +# Log level +LOG_LEVEL=$LOG_LEVEL_INFO +# Log color flag +LOG_COLOR_ENABLE=true +# Output file +OUT_FILE= +# Overwrite flag +OVERWRITE=false + +# ================ +# MAIN +# ================ +{ + parse_args "$@" + verify_system + inline +} + diff --git a/scripts/medley/medley.command b/scripts/medley/medley.command index f37ef8b8..210851a5 100755 --- a/scripts/medley/medley.command +++ b/scripts/medley/medley.command @@ -1,157 +1,1586 @@ -#!/bin/bash +#!/bin/sh +# shellcheck disable=SC2164,SC2181,SC2009,SC2034,SC2154 +# . ./medley_header.sh +# shellcheck shell=sh ############################################################################### # -# medley.sh - script for running Medley Interlisp on Linux/WSL. -# On Linux and WSL when using X Windows it just sets +# medley.sh - script for running Medley Interlisp on +# Linux/WSL/Cygwin/MacOS. On all platforms it just sets # up directories and environment variables and then calls -# run-medley. On WSL, there is an option to run without -# or around X Windows by using the XVnc and a VNC viewer +# maiko with the right arguments. On WSL, there is an option to +# run without or around X Windows by using the XVnc and a VNC viewer # on the Windows side. This script will start this VNC viewer # on the Windows side. # +# NOTE: This script is "compiled" using compile.sh (and inline.sh) from the +# component scripts (medley_*.sh). The top-level component is +# medley_main.sh. The other components are sourced (directly or +# indirectly) from medley_main.sh. +# +# Do not edit this script directly. Edit the component scripts and +# then recompile to get this "combined" script. You can also run +# the scripts by exec-ing the medley_main.sh script. This will allow +# testing of component modifications without having to compile. +# +# 2023-01-12 Frank Halasz +# 2024-04-29 Frank Halasz: Major overhaul +# +# Copyright 2023-2024 Interlisp.org +# +############################################################################### +############################################################################### +# +# medley_main.sh - "main" script for running Medley Interlisp on +# Linux/WSL/Cygwin/MacOS. On all platforms it just sets +# up directories and environment variables and then calls +# maiko with the right arguments. On WSL, there is an option to +# run without or around X Windows by using the XVnc and a VNC viewer +# on the Windows side. This script will start this VNC viewer +# on the Windows side. +# +# 2023-01-12 Frank Halasz +# 2024-04-29 Frank Halasz: Major overhaul +# +# Copyright 2023-2024 Interlisp.org +# +############################################################################### + +#set -x + +# +# +# Start off with some functions to determine what directory this script is being executed from +# +# +get_abs_filename() { + # $1 : relative filename + echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" +} + +# This function taken from +# https://stackoverflow.com/questions/29832037/how-to-get-script-directory-in-posix-sh +rreadlink() ( + + # Execute this function in a *subshell* to localize variables and the effect of `cd`. + + target=$1 + fname= + targetDir= + CDPATH= + + # Try to make the execution environment as predictable as possible: + # All commands below are invoked via `command`, so we must make sure that `command` + # itself is not redefined as an alias or shell function. + # (Note that command is too inconsistent across shells, so we don't use it.) + # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not even have + # an external utility version of it (e.g, Ubuntu). + # `command` bypasses aliases and shell functions and also finds builtins + # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for that + # to happen. + { \unalias command; \unset -f command; } >/dev/null 2>&1 + [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too. + + while :; do # Resolve potential symlinks until the ultimate target is found. + [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; } + command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path. + fname=$(command basename -- "$target") # Extract filename. + [ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/' + if [ -L "$fname" ]; then + # Extract [next] target path, which may be defined + # *relative* to the symlink's own directory. + # Note: We parse `ls -l` output to find the symlink target + # which is the only POSIX-compliant, albeit somewhat fragile, way. + target=$(command ls -l "$fname") + target=${target#* -> } + continue # Resolve [next] symlink target. + fi + break # Ultimate target reached. + done + targetDir=$(command pwd -P) # Get canonical dir. path + # Output the ultimate target's canonical path. + # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path. + if [ "$fname" = '.' ]; then + command printf '%s\n' "${targetDir%/}" + elif [ "$fname" = '..' ]; then + # Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied + # AFTER canonicalization. + command printf '%s\n' "$(command dirname -- "${targetDir}")" + else + command printf '%s\n' "${targetDir%/}/$fname" + fi +) + +get_script_dir() { + + # call this with $0 (from main script) as its (only) parameter + # if you need to preserve cwd, run this is a subshell since + # it can change cwd + + # set -x + + local_SCRIPT_PATH="$( get_abs_filename "$1" )"; + + while [ -h "$local_SCRIPT_PATH" ]; + do + cd "$( dirname -- "$local_SCRIPT_PATH"; )"; + local_SCRIPT_PATH="$( rreadlink "$local_SCRIPT_PATH" )"; + done + + cd "$( dirname -- "$local_SCRIPT_PATH"; )" > '/dev/null'; + local_SCRIPT_PATH="$( pwd; )"; + + # set +x + + echo "${local_SCRIPT_PATH}" +} + +# end of script directory functions +############################################################################### + + + +# figure out the script dir +SCRIPTDIR="$(get_script_dir "$0")" + +# Define some generally useful functions +# shellcheck source=./medley_utils.sh +# . "${SCRIPTDIR}/medley_utils.sh" +# shellcheck shell=sh +############################################################################### +# +# medley_utils.sh - script containing various useful functions for medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2023-01-23 Frank Halasz +# +# Copyright 2023 Interlisp.org +# +############################################################################### + +is_tput="$(which tput)" + +output_error_msg() { + local_oem_file="${TMPDIR:-/tmp}"/oem_$$ + echo "$1" >"${local_oem_file}" + while read -r line + do + if [ -n "${is_tput}" ]; + then + echo "$(${is_tput} setab 1)$(${is_tput} setaf 7)${line}$(${is_tput} sgr0)" + else + echo "$1" + fi + done <"${local_oem_file}" + rm -f "${local_oem_file}" +} + +check_for_dash_or_end() { + local_err_msg=""; + if [ -z "$2" ] || [ "$2" = "--" ] + then + local_err_msg="Error: the flag \"$1\" requires a value. +Value is missing." + usage "${local_err_msg}" + else + case "$2" in + -*) + local_err_msg="Error: either the value for flag \"${1}\" is missing OR +the value begins with a \"-\", which is not allowed." + usage "${local_err_msg}" + ;; + esac + fi +} + +check_file_writeable_or_creatable() { + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + local_err_msg="" + if [ -e "$%2" ] + then + if [ ! -f "$2" ] + then + local_err_msg="Error: File ${local_msg_core} is not a regular file. +It is either a directory or a device file of some sort. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + elif [ ! -w "$2" ] + then + local_err_msg="Error: File ${local_msg_core} exists but is not writeable +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi + else + if [ ! -w "$(dirname -- "$2")" ] + then + local_err_msg="Error: File ${local_msg_core} cannot be created because +its directory either doen't exist or is not writeable. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi + fi +} + +check_dir_writeable_or_creatable() { + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + local_err_msg="" + if [ -e "$%2" ] + then + if [ ! -d "$2" ] + then + local_err_msg="Error: ${local_msg_core} exists but is not a directory. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + elif [ ! -w "$2" ] + then + local_err_msg="Error: Directory ${local_msg_core} exists but is not writeable +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi + else + if [ ! -w "$(dirname -- "$2")" ] + then + local_err_msg="Error: Directory ${local_msg_core} cannot be created because +its directory either doesn't exist or is not writeable. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi + fi +} + + +check_file_readable() { + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + if [ ! -r "$2" ] + then + local_err_msg="Error: File ${local_msg_core} +either doesn't exist or is not readable. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi +} + +check_dir_exists() { + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + if [ -e "$2" ] + then + if [ ! -d "$2" ] + then + local_err_msg="Error: Pathname ${local_msg_core} exists but is not a directory. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + elif [ ! -r "$2" ] + then + local_err_msg="Error: Directory ${local_msg_core} exists but is not readable. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi + fi +} + +parse_nethub_data() { + nh_host="" + nh_port="" + nh_mac="" + nh_debug="" + # + x="${1%:}:" + nh_host="${x%%:*}" + x="${x#"${nh_host}":*}" + nh_port="${x%%:*}" + if [ "${nh_port}" = "${x}" ]; then nh_port=""; return 0; fi + x="${x#"${nh_port}":*}" + nh_mac="${x%%:*}" + if [ "${nh_mac}" = "${x}" ]; then nh_mac=""; return 0; fi + nh_debug="${x#"${nh_mac}":*}" + if [ "${nh_debug}" = "${x}" ]; then nh_debug=""; return 0; fi + nh_debug="${nh_debug%:}" + return 0 +} + + +MEDLEYDIR="$(cd "${SCRIPTDIR}/../.."; pwd)" +export MEDLEYDIR +IL_DIR="$(cd "${MEDLEYDIR}/.."; pwd)" + +# Are we running under WSL or Darwin or Cygwin? +# +wsl=false +darwin=false +cygwin=false + +if [ "$(uname)" = "Darwin" ] +then + darwin=true +elif [ "$(uname -s | head --bytes 6)" = "CYGWIN" ] +then + cygwin=true +elif [ -e "/proc/version" ] && grep --ignore-case --quiet Microsoft /proc/version +then + wsl=true + wsl_ver=0 + # WSL2 + grep --ignore-case --quiet wsl /proc/sys/kernel/osrelease + if [ $? -eq 0 ]; + then + wsl_ver=2 + else + # WSL1 + grep --ignore-case --quiet microsoft /proc/sys/kernel/osrelease + if [ $? -eq 0 ] + then + if [ "$(uname -m)" = "x86_64" ] + then + wsl_ver=1 + else + err_msg="ERROR: Running Medley on WSL1 requires an x86_64-based PC. +This is not an x86_64-based PC. +Exiting" + output_error_msg "${err_msg}" + exit 23 + fi + fi + fi +fi + +# process config file and args +# shellcheck source=./medley_configfile.sh +# . "${SCRIPTDIR}/medley_configfile.sh" +# shellcheck shell=sh +############################################################################### +# +# medley_configfile.sh - script for processing the config file for the +# medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2024-04-20 Frank Halasz +# +# Copyright 2024 Interlisp.org +# +############################################################################### + +config_file="" + +# look thru args looking to see if a config file was specified +j=1 +jmax=$# +while [ "$j" -le "$jmax" ] +do + if [ "$(eval "printf %s \${${j}}")" = "-c" ] || [ "$(eval "printf %s \${${j}}")" = "--config" ] + then + k=$(( j + 1 )) + config_file="$(eval "printf %s \${${k}}")" + if [ ! "${config_file}" = "-" ] && [ ! -f "${config_file}" ] + then + echo "Error: specified config file \"${config_file}\" not found." + echo "Exiting." + exit 52 + fi + j=$(( j + 1 )) + fi + j=$(( j + 1 )) +done + +# if no config file specified, use the defaults (if they exist) +if [ -z "${config_file}" ] +then + for f in "${HOME}/.medley_config" "${MEDLEYDIR}/.medley_config" + do + if [ -f "$f" ] + then + config_file="$f" + fi + done +fi + +# add marker to separate config file args from command line args +set -- "--start_cl_args" "--start_cl_args" "$@" + +# if there is a config file and its not been suppressed with "-", +# read the config file (in reverse order) and add the first two items on each line +# to the arguments array +if [ -n "${config_file}" ] && [ ! "${config_file}" = "-" ] +then + rev_config_file="${TMPDIR:-/tmp}"/.medley_config_$$ + # reverse order of lines in medley config file + sed '1!x;H;1h;$!d;g' < "${config_file}" >"${rev_config_file}" + while read -r arg1 arg2 + do + if [ -n "${arg2}" ] + then + arg2="$(echo "${arg2}" | sed s/\"//g)" + set -- "${arg2}" "$@" + fi + if [ -n "${arg1}" ] + then + set -- "${arg1}" "$@" + fi + done < "${rev_config_file}" + rm -f "${rev_config_file}" +fi + + + +# shellcheck source=./medley_args.sh +# . "${SCRIPTDIR}/medley_args.sh" +# shellcheck shell=sh +# shellcheck disable=SC2034,SC2154,SC2164 +############################################################################### +# +# medley_args.sh - script for processing the args to medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# # 2023-01-12 Frank Halasz # # Copyright 2023 Interlisp.org # ############################################################################### -#set -x - -# functions to discover what directory this script is being executed from -get_abs_filename() { - # $1 : relative filename - echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" -} - -get_script_dir() { - - # call this with ${BASH_SOURCE[0]:-$0} as its (only) parameter - - # set -x - - local SCRIPT_PATH="$( get_abs_filename "$1" )"; - - pushd . > '/dev/null'; - - while [ -h "$SCRIPT_PATH" ]; - do - cd "$( dirname -- "$SCRIPT_PATH"; )"; - SCRIPT_PATH="$( readlink -f -- "$SCRIPT_PATH"; )"; - done - - cd "$( dirname -- "$SCRIPT_PATH"; )" > '/dev/null'; - SCRIPT_PATH="$( pwd; )"; - - popd > '/dev/null'; - - # set +x - - echo "${SCRIPT_PATH}" -} - -SCRIPTDIR=$(get_script_dir "${BASH_SOURCE[0]:-$0}") -# Define some generally useful functions -source ${SCRIPTDIR}/medley_utils.sh - -export MEDLEYDIR=$(cd ${SCRIPTDIR}; cd ../..; pwd) -IL_DIR=$(cd ${MEDLEYDIR}; cd ..; pwd) -export LOGINDIR=${HOME}/il - -# Are we running under Docker or WSL or Darwin or Cygwin? +# load usage function +# shellcheck source=./medley_usage.sh +# . "${SCRIPTDIR}/medley_usage.sh" +# shellcheck shell=sh +# shellcheck disable=SC2154 +############################################################################### # -docker=false -wsl=false -darwin=false +# medley_useage.sh - script defining the "usage" for medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2023-01-21 Frank Halasz +# +# Copyright 2023 Interlisp.org +# +############################################################################### -if [ "$(uname)" = "Darwin" ]; -then - darwin=true -elif [ -n "${MEDLEY_DOCKER_BUILD_DATE}" ]; -then - docker='true' -elif [ $(uname -s | head --bytes 6) != "CYGWIN" ]; -then - wsl_ver=0 - # WSL2 - grep --ignore-case --quiet wsl /proc/sys/kernel/osrelease - if [ $? -eq 0 ]; + +PAGER=$( if [ -n "$(which more)" ]; then echo "more"; else echo "cat"; fi) + +usage() { + usage_msg_path=/tmp/msg-$$ + + if [ "${wsl}" = true ]; + then + wsl_incl="+w" + wsl_excl="-w" + else + wsl_incl="-w" + wsl_excl="+w" + fi + + if [ "${docker}" = true ]; + then + docker_incl="+d" + docker_excl="-d" + else + docker_incl="-d" + docker_excl="+d" + fi + + if [ "${windows}" = true ]; + then + windows_incl="+W" + windows_excl="-W" + else + windows_incl="-W" + windows_excl="+W" + fi + + if [ $# -ne 0 ]; + then + full_msg="In ${args_stage}: +$1" + { echo; output_error_msg "${full_msg}"; echo; } >> "${usage_msg_path}" + else + touch "${usage_msg_path}" + fi + + cat "${usage_msg_path}" - <\" argument to give this new instance a different id." - echo "Exiting" - exit 3 -fi - -# Set LDEDESTSYSOUT env variable based on id -if [ -z ${LDEDESTSYSOUT} ]; -then - if [ "${run_id}" = "default" ]; + matching=$(ps ax | sed -e "/sed/d" -e "/ldex.*-id ${run_id_base}/p" -e "/ldesdl.*-id ${run_id_base}/p" -e d) + if [ -n "${matching}" ] then - export LDEDESTSYSOUT=${LOGINDIR}/vmem/lisp.virtualmem - else - export LDEDESTSYSOUT=${LOGINDIR}/vmem/lisp_${run_id}.virtualmem + err_msg="Another instance of Medley Interlisp is already running with the id \"${run_id}\". +Only a single instance with a given id can be run at the same time. +Please retry using the \"--id \" argument to give this new instance a different id. +Exiting" + output_error_msg "${err_msg}" + exit 3 fi +else + matching=$( \ + ps ax | \ + sed -e "/ldex.*-id ${run_id_base}[0-9]/s/^.*-id ${run_id_base}\([0-9]*\).*$/\\1/p" \ + -e "/ldesdl.*-id ${run_id_base}[0-9]/s/^.*-id ${run_id_base}\([0-9]*\).*$/\\1/p" \ + -e d \ + ) + max=0 + for n in $matching + do + if [ "$n" -gt "$max" ]; then max=$n; fi + done + max=$(( max + 1 )) + run_id="${run_id_base}${max}" fi -# Create LOGINDIR if necessary -if [ ! -e ${LOGINDIR} ]; +# Run medley +# shellcheck source=./medley_run.sh +# . "${SCRIPTDIR}/medley_run.sh" +# shellcheck shell=sh +# shellcheck disable=SC2154,SC2164,SC2086 +############################################################################### +# +# medley_run.sh - script for processing actually running maiko/medley +# for the medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2024-04-21 Frank Halasz +# +# Copyright 2024 Interlisp.org +# +############################################################################### + +# Figure out LOGINDIR situation +if [ -z "${logindir_arg}" ] then - mkdir -p ${LOGINDIR} -elif [ ! -d ${LOGINDIR} ]; + LOGINDIR="${HOME}/il" +else + LOGINDIR="${logindir_arg}" +fi +export LOGINDIR + +if [ ! -e "${LOGINDIR}" ]; +then + mkdir -p "${LOGINDIR}" +elif [ ! -d "${LOGINDIR}" ]; then echo "ERROR: Medley requires a directory named ${LOGINDIR}." - echo "But ${LOGINDIR} exists appears not be a directory." + echo "But ${LOGINDIR} exists but appears not be a directory." echo "Exiting" exit 2 fi -mkdir -p ${LOGINDIR}/vmem +mkdir -p "${LOGINDIR}"/vmem + +# Set LDEDESTSYSOUT env variable based on id +# if LDEDESRTSYSOUT has not already been set +# during arg processing +if [ -z "${vmem_arg}" ] +then + if [ "${run_id}" = "default" ] + then + LDEDESTSYSOUT="${LOGINDIR}/vmem/lisp.virtualmem" + else + LDEDESTSYSOUT="${LOGINDIR}/vmem/lisp_${run_id}.virtualmem" + fi +else + LDEDESTSYSOUT="${vmem_arg}" +fi +export LDEDESTSYSOUT + +# Figure out the sysout situation + +loadups_dir="${MEDLEYDIR}/loadups" +if [ -z "${sysout_arg}" ] +then + if [ -f "${LDEDESTSYSOUT}" ] + then + src_sysout="${LDEDESTSYSOUT}" + else + src_sysout="${loadups_dir}/full.sysout" + fi +else + case "${sysout_arg}" in + lisp | full | apps) + if [ ! -d "${loadups_dir}" ] + then + err_msg="Error: The sysout argument --${sysout_arg} was specified in ${sysout_stage}, +but the directory \"${loadups_dir}\" where ${sysout_arg}.sysout is supposed to be located +cannot be found. +Exiting." + output_error_msg "${err_msg}" + exit 62 + fi + src_sysout="${loadups_dir}/${sysout_arg}.sysout" + ;; + *) + src_sysout="${sysout_arg}" + ;; + esac +fi +if [ ! -f "${src_sysout}" ] +then + err_msg="Error: Cannot find the specified sysout file \"${src_sysout}\". +Exiting." + output_error_msg "${err_msg}" +fi + +# Figure out screensize and geometry based on arguments +# shellcheck source=./medley_geometry.sh +# . "${SCRIPTDIR}/medley_geometry.sh" +# shellcheck shell=sh +# shellcheck disable=SC2154,SC2269 +############################################################################### +# +# medley_geometry.sh - script for computing the geometry and screensize +# parameters for a medley session +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2023-01-17 Frank Halasz +# +# Copyright 2023 Interlisp.org +# +############################################################################### + +if [ "${noscroll}" = false ]; +then + scroll=22 +else + scroll=0 +fi +if [ -n "${geometry}" ] && [ -n "${screensize}" ] +then + gw=$(expr "${geometry}" : "\([0-9]*\)x[0-9]*$") + gh=$(expr "${geometry}" : "[0-9]*x\([0-9]*\)$") + if [ -z "${gw}" ] || [ -z "${gh}" ] + then + err_msg="Error: Improperly formed -geometry or -dimension argument: ${geometry}" + usage "${err_msg}" + fi + geometry="${geometry}" + # + sw=$(expr "${screensize}" : "\([0-9]*\)x[0-9]*$") + sh=$(expr "${screensize}" : "[0-9]*x\([0-9]*\)$") + if [ -z "${sw}" ] || [ -z "${sh}" ] + then + err_msg="Error: Improperly formed -screensize argument: ${screensize}" + usage "${err_msg}" + fi + screensize="${screensize}" +elif [ -n "${geometry}" ] +then + gw=$(expr "${geometry}" : "\([0-9]*\)x[0-9]*$") + gh=$(expr "${geometry}" : "[0-9]*x\([0-9]*\)$") + if [ -n "${gw}" ] && [ -n "${gh}" ] + then + sw=$(( (((31+gw)/32)*32)-scroll )) + sh=$(( gh - scroll )) + geometry="${gw}x${gh}" + screensize="${sw}x${sh}" + else + err_msg="Error: Improperly formed -geometry or -dimension argument: ${geometry}" + usage "${err_msg}" + fi +elif [ -n "${screensize}" ] +then + sw=$(expr "${screensize}" : "\([0-9]*\)x[0-9]*$") + sh=$(expr "${screensize}" : "[0-9]*x\([0-9]*\)$") + if [ -n "${sw}" ] && [ -n "${sh}" ] + then + sw=$(( (31+sw)/32*32 )) + gw=$(( scroll+sw )) + gh=$(( scroll+sh )) + geometry="${gw}x${gh}" + screensize="${sw}x${sh}" + else + err_msg="Error: Improperly formed -screensize argument: ${screensize}" + usage "${err_msg}" + fi +else + screensize="1440x900" + if [ "${noscroll}" = false ]; + then + geometry="1462x922" + else + geometry="1440x900" + fi +fi + +# Figure out border width situation +borderwidth_flag="" +borderwidth_value="" +if [ -n "${borderwidth_arg}" ] +then + borderwidth_flag="-bw" + borderwidth_value="${borderwidth_arg}" +fi + +# Figure out pixelscale situation +pixelscale_flag="" +pixelscale_value="" +if [ -n "${pixelscale_arg}" ] +then + pixelscale_flag="-pixelscale" + pixelscale_value="${pixelscale_arg}" +fi + +# figure out greet files situation +if [ -z "${greet_arg}" ] +then + if [ "${sysout_arg}" = "apps" ] + then + LDEINIT="${MEDLEYDIR}/greetfiles/APPS-INIT.LCOM" + else + LDEINIT="${MEDLEYDIR}/greetfiles/MEDLEYDIR-INIT.LCOM" + fi +else + if [ "${greet_arg}" = "--nogreet--" ] + then + LDEINIT="${MEDLEYDIR}/greetfiles/NOGREET" + else + LDEINIT="${greet_arg}" + fi +fi +export LDEINIT + +# figure out noscroll situation +noscroll_arg="" +if [ "${noscroll}" = true ] +then + noscroll_arg="-noscroll" +fi + +# figure out -m situatiom +mem_flag="" +mem_value="" +if [ -n "${mem_arg}" ] +then + mem_flag="-m" + mem_value="${mem_arg}" +fi + +# figure out the nethub situation +nh_host_flag="" +nh_host_value="" +nh_port_flag="" +nh_port_value="" +nh_mac_flag="" +nh_mac_value="" +nh_debug_flag="" +nh_debug_value="" +if [ -n "${nh_host_arg}" ] +then + nh_host_flag="-nh-host" + nh_host_value="${nh_host_arg}" + if [ -n "${nh_port_arg}" ] + then + nh_port_flag="-nh-port" + nh_port_value="${nh_port_arg}" + fi + if [ -n "${nh_mac_arg}" ] + then + nh_mac_flag="-nh-mac" + nh_mac_value="${nh_mac_arg}" + fi + if [ -n "${nh_debug_arg}" ] + then + nh_debug_flag="-nh-loglevel" + nh_debug_value="${nh_debug_arg}" + fi +fi + +# figure out the keyboard type +if [ -z "${LDEKBDTYPE}" ]; then + export LDEKBDTYPE="X" +fi + +# figure out title situation +if [ ! "${run_id}" = default ] +then + title="$(printf %s "${title}" | sed -e "s/%i/:: ${run_id}/")" +else + title="$(printf %s "${title}" | sed -e "s/%i//")" +fi + + +# Figure out the maiko executable name +# used for loadups (ldeinit) +if [ -z "${maikoprog_arg}" ] +then + maikoprog_arg="lde" +fi + +# Figure out the maiko directory maiko +check_if_maiko_dir () { + if [ -d "$1/bin" ] + then + cd "$1/bin" + else + return 1 + fi + if [ -x ./osversion ] && [ -x ./machinetype ] + then + maiko_exe="$1/$(./osversion).$(./machinetype)/${maikoprog_arg}" + if [ -x "${maiko_exe}" ] + then + cd ${OLDPWD} + return 0 + fi + fi + maiko_exe="" + cd ${OLDPWD} + return 1 +} + +if [ -z "${maikodir_arg}" ] +then + if [ -d "${MEDLEYDIR}/maiko" ] && check_if_maiko_dir "${MEDLEYDIR}/maiko" + then + maikodir_arg="${MEDLEYDIR}/maiko" + elif [ -d "${MEDLEYDIR}/../maiko" ] && check_if_maiko_dir "${MEDLEYDIR}/../maiko" + then + maikodir_arg="$(cd "${MEDLEYDIR}/../maiko"; pwd)" + else + err_msg="ERROR: Cannot find the directory containing the Maiko emulator in either +\"${MEDLEYDIR}/maiko\" or \"${MEDLEYDIR}/../maiko\". +Please use the --maikodir argument to specify the correct Maiko directory. +Exiting." + output_error_msg "${err_msg}" + exit 53 + fi +elif ! check_if_maiko_dir "${maikodir_arg}" +then + err_msg="In ${maikodir_stage}: +ERROR: The value of the --maikodir argument is not in fact a directory containing +the Maiko emulator. Exiting." + output_error_msg "${err_msg}" + exit 53 +fi + +maiko="${maiko_exe}" + +# Define function to start up maiko given all arguments +# Arg to this function should be "$@", the main args +# array that at this point should just include the pass-on args +start_maiko() { + echo \ + \"${maiko}\" \"${src_sysout}\" \ + -id \"${run_id}\" \ + -title \"${title}\" \ + -g ${geometry} \ + -sc ${screensize} \ + ${borderwidth_flag} ${borderwidth_value} \ + ${pixelscale_flag} ${pixelscale_value} \ + ${noscroll_arg} \ + ${mem_flag} ${mem_value} \ + ${nh_host_flag} ${nh_host_value} \ + ${nh_port_flag} ${nh_port_value} \ + ${nh_mac_flag} ${nh_mac_value} \ + ${nh_debug_flag} ${nh_debug_value} \ + ${nofork_arg} \ + "$@" ; + echo "MEDLEYDIR: \"${MEDLEYDIR}\"" + echo "LOGINDIR: \"${LOGINDIR}\"" + echo "GREET FILE: \"${LDEINIT}\"" + echo "VMEM FILE: \"${LDEDESTSYSOUT}\"" + # + # Temp workaround for issues in Maiko sysout arg + # processing. See Issue #1702. FGH 2024-05-09 + # + LDESOURCESYSOUT="${src_sysout}" + export LDESOURCESYSOUT + # + # End work around + # + "${maiko}" "${src_sysout}" \ + -id "${run_id}" \ + -title "${title}" \ + -g "${geometry}" \ + -sc "${screensize}" \ + ${borderwidth_flag} ${borderwidth_value} \ + ${pixelscale_flag} ${pixelscale_value} \ + ${noscroll_arg} \ + ${mem_flag} ${mem_value} \ + ${nh_host_flag} ${nh_host_value} \ + ${nh_port_flag} ${nh_port_value} \ + ${nh_mac_flag} ${nh_mac_value} \ + ${nh_debug_flag} ${nh_debug_value} \ + ${nofork_arg} \ + "$@" ; + exit_code=$? +} + # temp fix for cygwin to workaround issue #1685 # 2024-04-29 -MEDLEYDIR_BASE="${MEDLEYDIR}" -if [ "$(uname -s | head --bytes 6)" = "CYGWIN" ] +if [ "${cygwin}" = true ] then MEDLEYDIR="${MEDLEYDIR}/" fi -# Call run-medley with or without vnc -if [[ ( ${darwin} = true ) || (( ${wsl} = false || ${use_vnc} = false ) && ${docker} = false) ]]; + +# Run maiko either directly or with vnc +if [ "${wsl}" = true ] && [ "${use_vnc}" = true ] then - # If not using vnc, just call run-medley - ${MEDLEYDIR_BASE}/run-medley -id "${run_id}" -title "${title}" ${geometry} ${screensize} ${run_args[@]} + # do the vnc thing on wsl (if called for) + # shellcheck source=./medley_vnc.sh +# . "${SCRIPTDIR}/medley_vnc.sh" +# shellcheck shell=sh +# shellcheck disable=SC2154,SC2162 +############################################################################### +# +# medley_vnc.sh - script for running Medley Interlisp on WSL using Xvnc +# on the Linux side and a vncviewer on the Windows side. +# This script run under Linux will start the right apps +# on both the Linux and Windows sides. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2023-01-12 Frank Halasz +# +# Copyright 2023 Interlisp.org +# +############################################################################### + + ip_addr() { + ip -4 -br address show dev eth0 | awk '{print $3}' | sed 's-/.*$--' + } + + find_open_display() { + local_ctr=1 + local_result=-1 + while [ ${local_ctr} -lt 64 ]; + do + if [ ! -e /tmp/.X${local_ctr}-lock ]; + then + local_result=${local_ctr} + break + else + local_ctr=$(( local_ctr+1 )) + fi + done + echo ${local_result} + } + + find_open_port() { + local_ctr=5900 + local_result=-1 + while [ ${local_ctr} -lt 6000 ]; + do + if [ "${wsl}" = true ] && [ "${wsl_ver}" -eq 1 ] + then + netstat.exe -a -n | awk '{ print $2 }' | grep -q ":${local_ctr}\$" + else + ss -a | grep -q "LISTEN.*:${local_ctr}[^0-9]" + fi + if [ $? -eq 1 ]; + then + local_result=${local_ctr} + break + else + local_ctr=$(( local_ctr+1 )) + fi + done + echo ${local_result} + } + + # + # Make sure prequisites for vnc support in wsl are in place + # + if [ "${use_vnc}" = "true" ]; + then + win_userprofile="$(cmd.exe /c "/dev/null)" + vnc_dir="$(wslpath "${win_userprofile}")/AppData/Local/Interlisp" + vnc_exe="vncviewer64-1.12.0.exe" + if [ "$(which Xvnc)" = "" ] || [ "$(Xvnc -version 2>&1 | grep -iq tigervnc; echo $?)" -eq 1 ] + then + echo "Error: The -v or --vnc flag was set." + echo "But it appears that that TigerVNC \(Xvnc\) has not been installed." + echo "Please install TigerVNC using \"sudo apt install tigervnc-standalone-server tigervnc-xorg-extension\"" + echo "Exiting." + exit 4 + elif [ ! -e "${vnc_dir}/${vnc_exe}" ]; + then + if [ -e "${IL_DIR}/wsl/${vnc_exe}" ]; + then + # make sure TigerVNC viewer is in a Windows (not Linux) directory. If its in a Linux directory + # there will be a long delay when it starts up + mkdir -p "${vnc_dir}" + cp -p "${IL_DIR}/wsl/${vnc_exe}" "${vnc_dir}/${vnc_exe}" + else + loop_done=false + while [ "${loop_done}" = "false" ] + do + echo "TigerVnc viewer is required by the -vnc option but is not installed." + echo "Ok to download from SourceForge? [y, Y, n or N, default n] " + read resp + if [ -z "${resp}" ]; then resp=n; fi + case "${resp}" in + n* | N* ) + echo "Ok. You can download the Tiger VNC viewer \(v1.12.0\) .exe yourself and " + echo "place it in ${vnc_dir}/${vnc_exe}. Then retry." + echo "Exiting." + exit 5 + ;; + y* | Y* ) + wget -P "${vnc_dir}" https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe + loop_done=true + ;; + * ) + echo "Answer not one of Y, y, N, or n. Retry." + ;; + esac + done + fi + fi + fi + # + # Start the log file so we can trace any issues with vnc, etc + # + LOG="${LOGINDIR}/logs/medley_${run_id}.log" + mkdir -p "$(dirname -- "${LOG}")" + echo "START" >"${LOG}" + # + # + #set -x + # are we running in background - used for pretty-fying the echos + case $(ps -o stat= -p $$) in + *+*) bg=false ;; + *) bg=true ;; + esac + # + # find an unused display and an available port + # + #set -x + OPEN_DISPLAY="$(find_open_display)" + if [ "${OPEN_DISPLAY}" -eq -1 ]; + then + echo "Error: cannot find an unused DISPLAY between 1 and 63" + echo "Exiting" + exit 33 + else + if [ "${bg}" = true ]; then echo; fi + echo "Using DISPLAY=:${OPEN_DISPLAY}" + fi + DISPLAY=":${OPEN_DISPLAY}" + export DISPLAY + VNC_PORT="$(find_open_port)" + export VNC_PORT + if [ "${VNC_PORT}" -eq -1 ]; + then + echo "Error: cannot find an unused port between 5900 and 5999" + echo "Exiting" + exit 33 + else + echo "Using VNC_PORT=${VNC_PORT}" + fi + # + # Start the Xvnc server + # + mkdir -p "${LOGINDIR}"/logs + /usr/bin/Xvnc "${DISPLAY}" \ + -rfbport "${VNC_PORT}" \ + -geometry "${geometry}" \ + -SecurityTypes None \ + -NeverShared \ + -DisconnectClients=0 \ + -desktop "${title}" \ + --MaxDisconnectionTime=10 \ + >> "${LOG}" 2>&1 & + + sleep .5 + # + # Run Maiko in background, handing over the pass-on args which are all thats left in the main args array + # + { + start_maiko "$@" + if [ -n "$(pgrep -f "${vnc_exe}.*:${VNC_PORT}")" ]; then vncconfig -disconnect; fi + } & + + # + # Start the vncviewer on the windows side + # + + # First give medley time to startup + # sleep .25 + # SLeep appears not to be needed, but faster/slower machines ???? + # FGH 2023-02-08 + + # Then start vnc viewer on Windows side + vncv_loc=$(( OPEN_DISPLAY * 50 )) + start_time=$(date +%s) + "${vnc_dir}"/${vnc_exe} \ + -geometry "+${vncv_loc}+${vncv_loc}" \ + -ReconnectOnError=off \ + −AlertOnFatalError=off \ + "$(ip_addr)":"${VNC_PORT}" \ + >>"${LOG}" 2>&1 & + wait $! + if [ $(( $(date +%s) - start_time )) -lt 5 ] + then + if [ -z "$(pgrep -f "Xvnc ${DISPLAY}")" ] + then + echo "Xvnc server failed to start." + echo "See log file at ${LOG}" + echo "Exiting" + exit 3 + else + echo "VNC viewer failed to start."; + echo "See log file at ${LOG}"; + echo "Exiting" ; + exit 4; + fi + fi + # + # Done, "Go back" to medley_run.sh + # + true + +####################################### else - # do the vnc thing on wsl or docker - source ${SCRIPTDIR}/medley_vnc.sh + # If not using vnc, just exec maiko directly + # handing over the pass-on args which are all thats left in the main args array + start_maiko "$@" fi - - - +exit ${exit_code} diff --git a/scripts/medley/medley_args.sh b/scripts/medley/medley_args.sh index 82c9a742..5f0095aa 100755 --- a/scripts/medley/medley_args.sh +++ b/scripts/medley/medley_args.sh @@ -1,3 +1,6 @@ +#!only-to-be-sourced +# shellcheck shell=sh +# shellcheck disable=SC2034,SC2154,SC2164 ############################################################################### # # medley_args.sh - script for processing the args to medley.sh script. @@ -12,115 +15,232 @@ ############################################################################### # load usage function -source ${SCRIPTDIR}/medley_usage.sh +# shellcheck source=./medley_usage.sh +. "${SCRIPTDIR}/medley_usage.sh" +args_stage="config file" # Defaults -apps_flag=false -err_msg="" -full_flag=false geometry="" greet_specified=false -lisp_flag=false -noscroll=false pass_args=false -run_args=() run_id="default" screensize="" -sysout_flag=false sysout_arg="" -title="Medley Interlisp" +sysout_stage="" +title="Medley Interlisp %i" use_vnc=false windows=false +maikodir_arg="" +maikodir_stage="" +maikoprog_arg="" +greet_arg="" +noscroll=false +display_arg="" +vmem_arg="" +mem_arg="" +maiko_args="" +logindir_arg="" +nh_host_arg="" +nh_port_arg="" +nh_mac_arg="" +nh_debug_arg="" +pixelscale_arg="" +borderwidth_arg="" + + +# Add marker at end of args so we can accumulate pass-on args in args array +set -- "$@" "--start_of_pass_args" # Loop thru args and process while [ "$#" -ne 0 ]; do - if [ ${pass_args} = false ]; + if [ "${pass_args}" = false ]; then case "$1" in -a | --apps) sysout_arg="apps" - apps_flag=true + sysout_stage="${args_stage}" + ;; + -c | --config) + # already handled so just skip both flag and value + shift; ;; -d | --display) - check_for_dash_or_end "$1" "$2" - run_args+=(-d $2) + if [ "$2" = "-" ] + then + display="" + else + check_for_dash_or_end "$1" "$2" + display_arg="$2" + fi shift ;; -e | --interlisp) - export MEDLEY_EXEC="inter" + case "$2" in + -) + MEDLEY_EXEC="" + shift + ;; + +) + export MEDLEY_EXEC="inter" + shift + ;; + *) + export MEDLEY_EXEC="inter" + ;; + esac ;; -f | --full) - sysout_arg="-full" - full_flag=true + sysout_arg="full" + sysout_stage="${args_stage}" ;; -g | --geometry) - check_for_dash_or_end "$1" "$2" - geometry="$2" + if [ "$2" = "-" ] + then + geometry="" + else + check_for_dash_or_end "$1" "$2" + geometry="$2" + fi shift ;; -h | --help) usage ;; -i | --id) - if [ "$2" = "-" ]; + if [ "$2" = "-" ] then - run_id=$( basename ${MEDLEYDIR} ) - elif [ "$2" = "--" ]; + run_id="default" + elif [ "$2" = "--" ] then - run_id=$(cd ${MEDLEYDIR}; cd ..; basename $(pwd)) + run_id="$( basename "${MEDLEYDIR}" )" + elif [ "$2" = "---" ] + then + run_id="$(cd "${MEDLEYDIR}/.."; basename "$(pwd)")" else check_for_dash_or_end "$1" "$2" - run_id=$(echo "$2" | sed s/[^A-Za-z0-9]//g) + run_id=$(echo "$2" | sed -e "s/++*\(.\)/\\1/g" -e "s/[^A-Za-z0-9+_]//g") fi shift ;; -k | --vmem) - check_for_dash_or_end "$1" "$2" - check_file_writeable_or_creatable "$1" "$2" - export LDEDESTSYSOUT="$2" + if [ "$2" = "-" ] + then + vmem_arg="" + else + check_for_dash_or_end "$1" "$2" + check_file_writeable_or_creatable "$1" "$2" + vmem_arg="$2" + fi shift ;; -l | --lisp) - sysout_arg="-lisp" - lisp_flag=true + sysout_arg="lisp" + sysout_stage="${args_stage}" ;; -m | --mem) - check_for_dash_or_end "$1" "$2" - run_args+=(-m $2) + if [ "$2" = "-" ] + then + mem_arg="" + else + check_for_dash_or_end "$1" "$2" + mem_arg="$2" + fi shift ;; -n | --noscroll) - noscroll=true - run_args+=("-noscroll") + case "$2" in + -) + noscroll=false + shift + ;; + +) + noscroll=true + shift + ;; + *) + noscroll=true + ;; + esac + ;; + -nh | --nethub) + case "$2" in + -:* | - ) + true + ;; + *) + check_for_dash_or_end "$1" "$2" + ;; + esac + parse_nethub_data "$2" + if [ "${nh_host}" = "-" ]; then nh_host_arg=""; else nh_host_arg="${nh_host}"; fi + if [ "${nh_port}" = "-" ]; then nh_port_arg=""; else nh_port_arg="${nh_port}"; fi + if [ "${nh_mac}" = "-" ]; then nh_mac_arg=""; else nh_mac_arg="${nh_mac}"; fi + if [ "${nh_debug}" = "-" ]; then nh_debug_arg=""; else nh_debug_arg="${nh_debug}"; fi + shift + ;; + -ps | --pixelscale) + if [ "$2" = "-" ] + then + pixelscale_arg="" + else + check_for_dash_or_end "$1" "$2" + pixelscale_arg="$2" + fi + shift ;; -r | --greet) - if [[ "$2" = "-" || "$2" = "--" ]]; + if [ "$2" = "-" ] || [ "$2" = "--" ] then - run_args+=("--nogreet") + greet_arg="--nogreet--" else check_for_dash_or_end "$1" "$2" check_file_readable "$1" "$2" - run_args+=("-greet" "$2") + greet_arg="$2" fi greet_specified='true' shift ;; -s | --screensize) - check_for_dash_or_end "$1" "$2" - screensize="$2" + if [ "$2" = "-" ] + then + screensize="" + else + check_for_dash_or_end "$1" "$2" + screensize="$2" + fi shift ;; -t | --title) - check_for_dash_or_end "$1" "$2" - if [ -n "$2" ]; then title="$2"; fi + if [ "$2" = "-" ] + then + title="" + else + check_for_dash_or_end "$1" "$2" + if [ -n "$2" ]; then title="$2"; fi + fi shift ;; + -u | --continue) + sysout_arg="" + sysout_stage="${args_stage}" + ;; -v | --vnc) - if [[ ${wsl} = true && $(uname -m) = x86_64 ]]; + case "$2" in + -) + use_vnc=false + shift + ;; + +) + use_vnc=true + shift + ;; + *) + use_vnc=true + ;; + esac + if [ "${use_vnc}" = true ] && { [ ! "${wsl}" = true ] || [ ! "$(uname -m)" = x86_64 ] ; } then - use_vnc=true - else echo "Warning: The -v or --vnc flag was set." echo "But the vnc option is only available when running on " echo "Windows System for Linux (wsl) on x86_64 machines." @@ -129,19 +249,33 @@ do fi ;; -x | --logindir) - if [[ "$2" = "-" || "$2" = "--" ]]; + if [ "$2" = "-" ] + then + logindir_arg="" + elif [ "$2" = "--" ] then check_dir_writeable_or_creatable "$1" "${MEDLEYDIR}/logindir" - LOGINDIR="${MEDLEYDIR}/logindir" + logindir_arg="${MEDLEYDIR}/logindir" else check_for_dash_or_end "$1" "$2" check_dir_writeable_or_creatable "$1" "$2" - LOGINDIR="$2" + logindir_arg="$2" fi shift ;; + -y | --sysout) + if [ "$2" = "-" ] + then + sysout_arg="" + else + check_for_dash_or_end "$1" "$2" + sysout_arg="$2" + fi + sysout_stage="${args_stage}" + shift + ;; -z | --man) - if [ ${darwin} = true ]; + if [ "${darwin}" = true ] then /usr/bin/man "${MEDLEYDIR}/docs/man-page/medley.1.gz" else @@ -149,79 +283,89 @@ do fi exit 0 ;; + -nf | -NF | --nofork) + # for use in loadups + case $2 in + -) + nofork_arg="" + ;; + +) + nofork_arg="-NF" + ;; + *) + nofork_arg="-NF" + ;; + esac + ;; + --maikodir) + # for use in loadups + check_for_dash_or_end "$1" "$2" + check_dir_exists "$1" "2" + maikodir_arg="$2" + maikodir_stage="${args_stage}" + shift; + ;; + -prog | --maikoprog) + # for use in loadups + check_for_dash_or_end "$1" "$2" + maikoprog_arg="$2" + shift + ;; --windows) # internal: called from Windows medley.ps1 (via docker) windows=true ;; + --start_cl_args) + # internal: used to separate config file args from command line args + args_stage="command line arguments" + pass_args=false + ;; + --start_of_pass_args) + # internal: used to mark end of args and start of accumulated pass-on args + shift + break + ;; --) pass_args=true ;; -*) - err_msg=("ERROR: Unknown flag: $1" ) - usage "${err_msg[@]}" + usage "ERROR: Unknown flag: $1" ;; *) # if matched the empty string, just ignore if [ -n "$1" ]; then - if [[ $# -eq 1 || "$2" = "--" ]]; + if [ $# -eq 1 ] || [ "$2" = "--" ] then - sysout_flag=true sysout_arg="$1" + sysout_stage="${args_stage}" else - err_msg=( - "ERROR: sysout argument must be last argument" - "or last argument before the \"--\" flag" - ) - usage "${err_msg[@]}" + err_msg="ERROR: unexpected argument \"$1\"" + usage "${err_msg}" fi fi ;; esac else - run_args+=("$1") + if [ "$1" = "--start_cl_args" ] + then + args_stage="command line arguments" + pass_args=false + elif [ "$1" = "--start_of_pass_args" ] + then + shift + break + else + # add pass-on args to end of args array + set -- "$@" "$1" + # maiko_args="${maiko_args} \"$1\"" + fi fi shift done -# Figure out screensize and geometry based on arguments -source ${SCRIPTDIR}/medley_geometry.sh - -# Figure out the sysout situation -ctr=0 -for x in ${lisp_flag} ${full_flag} ${apps_flag} ${sysout_flag}; -do - if [ "${x}" = "true" ]; - then - (( ctr++ )) - fi -done -if [ ${ctr} -gt 1 ]; -then - err_msg=( - "Error: only one sysout can be specified. Two or more sysouts were specified" - "via the -l (--lisp), -f (--full), -a (--apps) flags and/or a sysout filename" - ) - usage "${err_msg[@]}" -fi -if [ "${sysout_arg}" = "apps" ]; -then - export LDESRCESYSOUT="${MEDLEYDIR}/loadups/apps.sysout" - if [ "${greet_specified}" = "false" ]; - then - export LDEINIT="${MEDLEYDIR}/greetfiles/APPS-INIT.LCOM" - fi -else - # pass on to run-medley - unset LDESRCESYSOUT - if [ -n "${sysout_arg}" ]; - then - run_args+=("${sysout_arg}") - fi -fi - # if running on WSL1, force use_vnc -if [[ ${wsl} = true && ${wsl_ver} -eq 1 ]]; +if [ "${wsl}" = true ] && [ "${wsl_ver}" -eq 1 ] then use_vnc=true fi diff --git a/scripts/medley/medley_configfile.sh b/scripts/medley/medley_configfile.sh new file mode 100644 index 00000000..c6345519 --- /dev/null +++ b/scripts/medley/medley_configfile.sh @@ -0,0 +1,78 @@ +#!only-to-be-sourced +# shellcheck shell=sh +############################################################################### +# +# medley_configfile.sh - script for processing the config file for the +# medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2024-04-20 Frank Halasz +# +# Copyright 2024 Interlisp.org +# +############################################################################### + +config_file="" + +# look thru args looking to see if a config file was specified +j=1 +jmax=$# +while [ "$j" -le "$jmax" ] +do + if [ "$(eval "printf %s \${${j}}")" = "-c" ] || [ "$(eval "printf %s \${${j}}")" = "--config" ] + then + k=$(( j + 1 )) + config_file="$(eval "printf %s \${${k}}")" + if [ ! "${config_file}" = "-" ] && [ ! -f "${config_file}" ] + then + echo "Error: specified config file \"${config_file}\" not found." + echo "Exiting." + exit 52 + fi + j=$(( j + 1 )) + fi + j=$(( j + 1 )) +done + +# if no config file specified, use the defaults (if they exist) +if [ -z "${config_file}" ] +then + for f in "${HOME}/.medley_config" "${MEDLEYDIR}/.medley_config" + do + if [ -f "$f" ] + then + config_file="$f" + fi + done +fi + +# add marker to separate config file args from command line args +set -- "--start_cl_args" "--start_cl_args" "$@" + +# if there is a config file and its not been suppressed with "-", +# read the config file (in reverse order) and add the first two items on each line +# to the arguments array +if [ -n "${config_file}" ] && [ ! "${config_file}" = "-" ] +then + rev_config_file="${TMPDIR:-/tmp}"/.medley_config_$$ + # reverse order of lines in medley config file + sed '1!x;H;1h;$!d;g' < "${config_file}" >"${rev_config_file}" + while read -r arg1 arg2 + do + if [ -n "${arg2}" ] + then + arg2="$(echo "${arg2}" | sed s/\"//g)" + set -- "${arg2}" "$@" + fi + if [ -n "${arg1}" ] + then + set -- "${arg1}" "$@" + fi + done < "${rev_config_file}" + rm -f "${rev_config_file}" +fi + + + diff --git a/scripts/medley/medley_geometry.sh b/scripts/medley/medley_geometry.sh index c9610237..e2b0fc62 100755 --- a/scripts/medley/medley_geometry.sh +++ b/scripts/medley/medley_geometry.sh @@ -1,3 +1,6 @@ +#!only-to-be-sourced +# shellcheck shell=sh +# shellcheck disable=SC2154,SC2269 ############################################################################### # # medley_geometry.sh - script for computing the geometry and screensize @@ -12,68 +15,66 @@ # ############################################################################### -if [ ${noscroll} = false ]; +if [ "${noscroll}" = false ]; then scroll=22 else scroll=0 fi -if [[ -n ${geometry} && -n ${screensize} ]]; +if [ -n "${geometry}" ] && [ -n "${screensize}" ] then gw=$(expr "${geometry}" : "\([0-9]*\)x[0-9]*$") gh=$(expr "${geometry}" : "[0-9]*x\([0-9]*\)$") - if [[ -z "${gw}" || -z "${gh}" ]]; + if [ -z "${gw}" ] || [ -z "${gh}" ] then - echo "Error: Improperly formed -geometry or -dimension argument: ${geometry}" - echo "Exiting" - exit 7 + err_msg="Error: Improperly formed -geometry or -dimension argument: ${geometry}" + usage "${err_msg}" fi - geometry="-g ${geometry}" + geometry="${geometry}" # sw=$(expr "${screensize}" : "\([0-9]*\)x[0-9]*$") sh=$(expr "${screensize}" : "[0-9]*x\([0-9]*\)$") - if [[ -z "${sw}" || -z "${sh}" ]]; + if [ -z "${sw}" ] || [ -z "${sh}" ] then - echo "Error: Improperly formed -screensize argument: ${screensize}" - echo "Exiting" - exit 7 + err_msg="Error: Improperly formed -screensize argument: ${screensize}" + usage "${err_msg}" fi - screensize="-sc ${screensize}" -elif [[ -n ${geometry} ]]; + screensize="${screensize}" +elif [ -n "${geometry}" ] then gw=$(expr "${geometry}" : "\([0-9]*\)x[0-9]*$") gh=$(expr "${geometry}" : "[0-9]*x\([0-9]*\)$") - if [ -n "${gw}" -a -n "${gh}" ] ; then - sw=$(( ((31+${gw})/32*32) - ${scroll} )) - sh=$(( ${gh} - ${scroll} )) - geometry="-g ${gw}x${gh}" - screensize="-sc ${sw}x${sh}" + if [ -n "${gw}" ] && [ -n "${gh}" ] + then + sw=$(( (((31+gw)/32)*32)-scroll )) + sh=$(( gh - scroll )) + geometry="${gw}x${gh}" + screensize="${sw}x${sh}" else - echo "Error: Improperly formed -geometry or -dimension argument: ${geometry}" - echo "Exiting" - exit 7 + err_msg="Error: Improperly formed -geometry or -dimension argument: ${geometry}" + usage "${err_msg}" fi -elif [[ -n ${screensize} ]]; +elif [ -n "${screensize}" ] then sw=$(expr "${screensize}" : "\([0-9]*\)x[0-9]*$") sh=$(expr "${screensize}" : "[0-9]*x\([0-9]*\)$") - if [ -n "${sw}" -a -n "${sh}" ] ; then - sw=$(( (31+$sw)/32*32 )) - gw=$(( ${scroll}+${sw} )) - gh=$(( ${scroll}+${sh} )) - geometry="-g ${gw}x${gh}" - screensize="-sc ${sw}x${sh}" + if [ -n "${sw}" ] && [ -n "${sh}" ] + then + sw=$(( (31+sw)/32*32 )) + gw=$(( scroll+sw )) + gh=$(( scroll+sh )) + geometry="${gw}x${gh}" + screensize="${sw}x${sh}" else - echo "Error: Improperly formed -screensize argument: ${screensize}" - echo "Exiting" - exit 7 + err_msg="Error: Improperly formed -screensize argument: ${screensize}" + usage "${err_msg}" fi else - screensize="-sc 1440x900" - if [ ${noscroll} = false ]; + screensize="1440x900" + if [ "${noscroll}" = false ]; then - geometry="-g 1462x922" + geometry="1462x922" else - geometry="-g 1440x900" + geometry="1440x900" fi fi diff --git a/scripts/medley/medley_header.sh b/scripts/medley/medley_header.sh new file mode 100644 index 00000000..a088403c --- /dev/null +++ b/scripts/medley/medley_header.sh @@ -0,0 +1,28 @@ +#!only-to-be-sourced +# shellcheck shell=sh +############################################################################### +# +# medley.sh - script for running Medley Interlisp on +# Linux/WSL/Cygwin/MacOS. On all platforms it just sets +# up directories and environment variables and then calls +# maiko with the right arguments. On WSL, there is an option to +# run without or around X Windows by using the XVnc and a VNC viewer +# on the Windows side. This script will start this VNC viewer +# on the Windows side. +# +# NOTE: This script is "compiled" using compile.sh (and inline.sh) from the +# component scripts (medley_*.sh). The top-level component is +# medley_main.sh. The other components are sourced (directly or +# indirectly) from medley_main.sh. +# +# Do not edit this script directly. Edit the component scripts and +# then recompile to get this "combined" script. You can also run +# the scripts by exec-ing the medley_main.sh script. This will allow +# testing of component modifications without having to compile. +# +# 2023-01-12 Frank Halasz +# 2024-04-29 Frank Halasz: Major overhaul +# +# Copyright 2023-2024 Interlisp.org +# +############################################################################### diff --git a/scripts/medley/medley_main.sh b/scripts/medley/medley_main.sh new file mode 100755 index 00000000..810b45d7 --- /dev/null +++ b/scripts/medley/medley_main.sh @@ -0,0 +1,207 @@ +#!/bin/sh +# shellcheck disable=SC2164,SC2181,SC2009,SC2034,SC2154 +. ./medley_header.sh +############################################################################### +# +# medley_main.sh - "main" script for running Medley Interlisp on +# Linux/WSL/Cygwin/MacOS. On all platforms it just sets +# up directories and environment variables and then calls +# maiko with the right arguments. On WSL, there is an option to +# run without or around X Windows by using the XVnc and a VNC viewer +# on the Windows side. This script will start this VNC viewer +# on the Windows side. +# +# 2023-01-12 Frank Halasz +# 2024-04-29 Frank Halasz: Major overhaul +# +# Copyright 2023-2024 Interlisp.org +# +############################################################################### + +#set -x + +# +# +# Start off with some functions to determine what directory this script is being executed from +# +# +get_abs_filename() { + # $1 : relative filename + echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" +} + +# This function taken from +# https://stackoverflow.com/questions/29832037/how-to-get-script-directory-in-posix-sh +rreadlink() ( + + # Execute this function in a *subshell* to localize variables and the effect of `cd`. + + target=$1 + fname= + targetDir= + CDPATH= + + # Try to make the execution environment as predictable as possible: + # All commands below are invoked via `command`, so we must make sure that `command` + # itself is not redefined as an alias or shell function. + # (Note that command is too inconsistent across shells, so we don't use it.) + # `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not even have + # an external utility version of it (e.g, Ubuntu). + # `command` bypasses aliases and shell functions and also finds builtins + # in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for that + # to happen. + { \unalias command; \unset -f command; } >/dev/null 2>&1 + [ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too. + + while :; do # Resolve potential symlinks until the ultimate target is found. + [ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; } + command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path. + fname=$(command basename -- "$target") # Extract filename. + [ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/' + if [ -L "$fname" ]; then + # Extract [next] target path, which may be defined + # *relative* to the symlink's own directory. + # Note: We parse `ls -l` output to find the symlink target + # which is the only POSIX-compliant, albeit somewhat fragile, way. + target=$(command ls -l "$fname") + target=${target#* -> } + continue # Resolve [next] symlink target. + fi + break # Ultimate target reached. + done + targetDir=$(command pwd -P) # Get canonical dir. path + # Output the ultimate target's canonical path. + # Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path. + if [ "$fname" = '.' ]; then + command printf '%s\n' "${targetDir%/}" + elif [ "$fname" = '..' ]; then + # Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied + # AFTER canonicalization. + command printf '%s\n' "$(command dirname -- "${targetDir}")" + else + command printf '%s\n' "${targetDir%/}/$fname" + fi +) + +get_script_dir() { + + # call this with $0 (from main script) as its (only) parameter + # if you need to preserve cwd, run this is a subshell since + # it can change cwd + + # set -x + + local_SCRIPT_PATH="$( get_abs_filename "$1" )"; + + while [ -h "$local_SCRIPT_PATH" ]; + do + cd "$( dirname -- "$local_SCRIPT_PATH"; )"; + local_SCRIPT_PATH="$( rreadlink "$local_SCRIPT_PATH" )"; + done + + cd "$( dirname -- "$local_SCRIPT_PATH"; )" > '/dev/null'; + local_SCRIPT_PATH="$( pwd; )"; + + # set +x + + echo "${local_SCRIPT_PATH}" +} + +# end of script directory functions +############################################################################### + + + +# figure out the script dir +SCRIPTDIR="$(get_script_dir "$0")" + +# Define some generally useful functions +# shellcheck source=./medley_utils.sh +. "${SCRIPTDIR}/medley_utils.sh" + +MEDLEYDIR="$(cd "${SCRIPTDIR}/../.."; pwd)" +export MEDLEYDIR +IL_DIR="$(cd "${MEDLEYDIR}/.."; pwd)" + +# Are we running under WSL or Darwin or Cygwin? +# +wsl=false +darwin=false +cygwin=false + +if [ "$(uname)" = "Darwin" ] +then + darwin=true +elif [ "$(uname -s | head --bytes 6)" = "CYGWIN" ] +then + cygwin=true +elif [ -e "/proc/version" ] && grep --ignore-case --quiet Microsoft /proc/version +then + wsl=true + wsl_ver=0 + # WSL2 + grep --ignore-case --quiet wsl /proc/sys/kernel/osrelease + if [ $? -eq 0 ]; + then + wsl_ver=2 + else + # WSL1 + grep --ignore-case --quiet microsoft /proc/sys/kernel/osrelease + if [ $? -eq 0 ] + then + if [ "$(uname -m)" = "x86_64" ] + then + wsl_ver=1 + else + err_msg="ERROR: Running Medley on WSL1 requires an x86_64-based PC. +This is not an x86_64-based PC. +Exiting" + output_error_msg "${err_msg}" + exit 23 + fi + fi + fi +fi + +# process config file and args +# shellcheck source=./medley_configfile.sh +. "${SCRIPTDIR}/medley_configfile.sh" +# shellcheck source=./medley_args.sh +. "${SCRIPTDIR}/medley_args.sh" + +# Process run_id +# if it doesn't end in #, make sure that there is not another instance currently running with this same id +# If it does end in #, find the right number to fill in for the # +run_id_base="${run_id%+}" +run_id_has_plus="${run_id#"${run_id_base}"}" +if [ -z "${run_id_has_plus}" ] +then + matching=$(ps ax | sed -e "/sed/d" -e "/ldex.*-id ${run_id_base}/p" -e "/ldesdl.*-id ${run_id_base}/p" -e d) + if [ -n "${matching}" ] + then + err_msg="Another instance of Medley Interlisp is already running with the id \"${run_id}\". +Only a single instance with a given id can be run at the same time. +Please retry using the \"--id \" argument to give this new instance a different id. +Exiting" + output_error_msg "${err_msg}" + exit 3 + fi +else + matching=$( \ + ps ax | \ + sed -e "/ldex.*-id ${run_id_base}[0-9]/s/^.*-id ${run_id_base}\([0-9]*\).*$/\\1/p" \ + -e "/ldesdl.*-id ${run_id_base}[0-9]/s/^.*-id ${run_id_base}\([0-9]*\).*$/\\1/p" \ + -e d \ + ) + max=0 + for n in $matching + do + if [ "$n" -gt "$max" ]; then max=$n; fi + done + max=$(( max + 1 )) + run_id="${run_id_base}${max}" +fi + +# Run medley +# shellcheck source=./medley_run.sh +. "${SCRIPTDIR}/medley_run.sh" diff --git a/scripts/medley/medley_run.sh b/scripts/medley/medley_run.sh new file mode 100644 index 00000000..78ddc9bf --- /dev/null +++ b/scripts/medley/medley_run.sh @@ -0,0 +1,320 @@ +#!only-to-be-sourced +# shellcheck shell=sh +# shellcheck disable=SC2154,SC2164,SC2086 +############################################################################### +# +# medley_run.sh - script for processing actually running maiko/medley +# for the medley.sh script. +# +# !!!! This script is meant to be SOURCEd from the scripts/medley.sh script. +# !!!! It should not be run as a standlone script. +# +# 2024-04-21 Frank Halasz +# +# Copyright 2024 Interlisp.org +# +############################################################################### + +# Figure out LOGINDIR situation +if [ -z "${logindir_arg}" ] +then + LOGINDIR="${HOME}/il" +else + LOGINDIR="${logindir_arg}" +fi +export LOGINDIR + +if [ ! -e "${LOGINDIR}" ]; +then + mkdir -p "${LOGINDIR}" +elif [ ! -d "${LOGINDIR}" ]; +then + echo "ERROR: Medley requires a directory named ${LOGINDIR}." + echo "But ${LOGINDIR} exists but appears not be a directory." + echo "Exiting" + exit 2 +fi +mkdir -p "${LOGINDIR}"/vmem + +# Set LDEDESTSYSOUT env variable based on id +# if LDEDESRTSYSOUT has not already been set +# during arg processing +if [ -z "${vmem_arg}" ] +then + if [ "${run_id}" = "default" ] + then + LDEDESTSYSOUT="${LOGINDIR}/vmem/lisp.virtualmem" + else + LDEDESTSYSOUT="${LOGINDIR}/vmem/lisp_${run_id}.virtualmem" + fi +else + LDEDESTSYSOUT="${vmem_arg}" +fi +export LDEDESTSYSOUT + +# Figure out the sysout situation + +loadups_dir="${MEDLEYDIR}/loadups" +if [ -z "${sysout_arg}" ] +then + if [ -f "${LDEDESTSYSOUT}" ] + then + src_sysout="${LDEDESTSYSOUT}" + else + src_sysout="${loadups_dir}/full.sysout" + fi +else + case "${sysout_arg}" in + lisp | full | apps) + if [ ! -d "${loadups_dir}" ] + then + err_msg="Error: The sysout argument --${sysout_arg} was specified in ${sysout_stage}, +but the directory \"${loadups_dir}\" where ${sysout_arg}.sysout is supposed to be located +cannot be found. +Exiting." + output_error_msg "${err_msg}" + exit 62 + fi + src_sysout="${loadups_dir}/${sysout_arg}.sysout" + ;; + *) + src_sysout="${sysout_arg}" + ;; + esac +fi +if [ ! -f "${src_sysout}" ] +then + err_msg="Error: Cannot find the specified sysout file \"${src_sysout}\". +Exiting." + output_error_msg "${err_msg}" +fi + +# Figure out screensize and geometry based on arguments +# shellcheck source=./medley_geometry.sh +. "${SCRIPTDIR}/medley_geometry.sh" + +# Figure out border width situation +borderwidth_flag="" +borderwidth_value="" +if [ -n "${borderwidth_arg}" ] +then + borderwidth_flag="-bw" + borderwidth_value="${borderwidth_arg}" +fi + +# Figure out pixelscale situation +pixelscale_flag="" +pixelscale_value="" +if [ -n "${pixelscale_arg}" ] +then + pixelscale_flag="-pixelscale" + pixelscale_value="${pixelscale_arg}" +fi + +# figure out greet files situation +if [ -z "${greet_arg}" ] +then + if [ "${sysout_arg}" = "apps" ] + then + LDEINIT="${MEDLEYDIR}/greetfiles/APPS-INIT.LCOM" + else + LDEINIT="${MEDLEYDIR}/greetfiles/MEDLEYDIR-INIT.LCOM" + fi +else + if [ "${greet_arg}" = "--nogreet--" ] + then + LDEINIT="${MEDLEYDIR}/greetfiles/NOGREET" + else + LDEINIT="${greet_arg}" + fi +fi +export LDEINIT + +# figure out noscroll situation +noscroll_arg="" +if [ "${noscroll}" = true ] +then + noscroll_arg="-noscroll" +fi + +# figure out -m situatiom +mem_flag="" +mem_value="" +if [ -n "${mem_arg}" ] +then + mem_flag="-m" + mem_value="${mem_arg}" +fi + +# figure out the nethub situation +nh_host_flag="" +nh_host_value="" +nh_port_flag="" +nh_port_value="" +nh_mac_flag="" +nh_mac_value="" +nh_debug_flag="" +nh_debug_value="" +if [ -n "${nh_host_arg}" ] +then + nh_host_flag="-nh-host" + nh_host_value="${nh_host_arg}" + if [ -n "${nh_port_arg}" ] + then + nh_port_flag="-nh-port" + nh_port_value="${nh_port_arg}" + fi + if [ -n "${nh_mac_arg}" ] + then + nh_mac_flag="-nh-mac" + nh_mac_value="${nh_mac_arg}" + fi + if [ -n "${nh_debug_arg}" ] + then + nh_debug_flag="-nh-loglevel" + nh_debug_value="${nh_debug_arg}" + fi +fi + +# figure out the keyboard type +if [ -z "${LDEKBDTYPE}" ]; then + export LDEKBDTYPE="X" +fi + +# figure out title situation +if [ ! "${run_id}" = default ] +then + title="$(printf %s "${title}" | sed -e "s/%i/:: ${run_id}/")" +else + title="$(printf %s "${title}" | sed -e "s/%i//")" +fi + + +# Figure out the maiko executable name +# used for loadups (ldeinit) +if [ -z "${maikoprog_arg}" ] +then + maikoprog_arg="lde" +fi + +# Figure out the maiko directory maiko +check_if_maiko_dir () { + if [ -d "$1/bin" ] + then + cd "$1/bin" + else + return 1 + fi + if [ -x ./osversion ] && [ -x ./machinetype ] + then + maiko_exe="$1/$(./osversion).$(./machinetype)/${maikoprog_arg}" + if [ -x "${maiko_exe}" ] + then + cd ${OLDPWD} + return 0 + fi + fi + maiko_exe="" + cd ${OLDPWD} + return 1 +} + +if [ -z "${maikodir_arg}" ] +then + if [ -d "${MEDLEYDIR}/maiko" ] && check_if_maiko_dir "${MEDLEYDIR}/maiko" + then + maikodir_arg="${MEDLEYDIR}/maiko" + elif [ -d "${MEDLEYDIR}/../maiko" ] && check_if_maiko_dir "${MEDLEYDIR}/../maiko" + then + maikodir_arg="$(cd "${MEDLEYDIR}/../maiko"; pwd)" + else + err_msg="ERROR: Cannot find the directory containing the Maiko emulator in either +\"${MEDLEYDIR}/maiko\" or \"${MEDLEYDIR}/../maiko\". +Please use the --maikodir argument to specify the correct Maiko directory. +Exiting." + output_error_msg "${err_msg}" + exit 53 + fi +elif ! check_if_maiko_dir "${maikodir_arg}" +then + err_msg="In ${maikodir_stage}: +ERROR: The value of the --maikodir argument is not in fact a directory containing +the Maiko emulator. Exiting." + output_error_msg "${err_msg}" + exit 53 +fi + +maiko="${maiko_exe}" + +# Define function to start up maiko given all arguments +# Arg to this function should be "$@", the main args +# array that at this point should just include the pass-on args +start_maiko() { + echo \ + \"${maiko}\" \"${src_sysout}\" \ + -id \"${run_id}\" \ + -title \"${title}\" \ + -g ${geometry} \ + -sc ${screensize} \ + ${borderwidth_flag} ${borderwidth_value} \ + ${pixelscale_flag} ${pixelscale_value} \ + ${noscroll_arg} \ + ${mem_flag} ${mem_value} \ + ${nh_host_flag} ${nh_host_value} \ + ${nh_port_flag} ${nh_port_value} \ + ${nh_mac_flag} ${nh_mac_value} \ + ${nh_debug_flag} ${nh_debug_value} \ + ${nofork_arg} \ + "$@" ; + echo "MEDLEYDIR: \"${MEDLEYDIR}\"" + echo "LOGINDIR: \"${LOGINDIR}\"" + echo "GREET FILE: \"${LDEINIT}\"" + echo "VMEM FILE: \"${LDEDESTSYSOUT}\"" + # + # Temp workaround for issues in Maiko sysout arg + # processing. See Issue #1702. FGH 2024-05-09 + # + LDESOURCESYSOUT="${src_sysout}" + export LDESOURCESYSOUT + # + # End work around + # + "${maiko}" "${src_sysout}" \ + -id "${run_id}" \ + -title "${title}" \ + -g "${geometry}" \ + -sc "${screensize}" \ + ${borderwidth_flag} ${borderwidth_value} \ + ${pixelscale_flag} ${pixelscale_value} \ + ${noscroll_arg} \ + ${mem_flag} ${mem_value} \ + ${nh_host_flag} ${nh_host_value} \ + ${nh_port_flag} ${nh_port_value} \ + ${nh_mac_flag} ${nh_mac_value} \ + ${nh_debug_flag} ${nh_debug_value} \ + ${nofork_arg} \ + "$@" ; + exit_code=$? +} + + +# temp fix for cygwin to workaround issue #1685 +# 2024-04-29 +if [ "${cygwin}" = true ] +then + MEDLEYDIR="${MEDLEYDIR}/" +fi + + +# Run maiko either directly or with vnc +if [ "${wsl}" = true ] && [ "${use_vnc}" = true ] +then + # do the vnc thing on wsl (if called for) + # shellcheck source=./medley_vnc.sh + . "${SCRIPTDIR}/medley_vnc.sh" +else + # If not using vnc, just exec maiko directly + # handing over the pass-on args which are all thats left in the main args array + start_maiko "$@" +fi +exit ${exit_code} diff --git a/scripts/medley/medley_usage.sh b/scripts/medley/medley_usage.sh index a0397b84..0dbdfa5d 100644 --- a/scripts/medley/medley_usage.sh +++ b/scripts/medley/medley_usage.sh @@ -1,3 +1,6 @@ +#!only-to-be-sourced +# shellcheck shell=sh +# shellcheck disable=SC2154 ############################################################################### # # medley_useage.sh - script defining the "usage" for medley.sh script. @@ -11,14 +14,13 @@ # ############################################################################### -PAGER=$( if [ -n $(which more) ]; then echo "more"; else echo "cat"; fi) + +PAGER=$( if [ -n "$(which more)" ]; then echo "more"; else echo "cat"; fi) usage() { - local err_msg - local msg_path=/tmp/msg-$$ - local lines=("$@") + usage_msg_path=/tmp/msg-$$ - if [ ${wsl} = true ]; + if [ "${wsl}" = true ]; then wsl_incl="+w" wsl_excl="-w" @@ -27,7 +29,7 @@ usage() { wsl_excl="+w" fi - if [ ${docker} = true ]; + if [ "${docker}" = true ]; then docker_incl="+d" docker_excl="-d" @@ -36,7 +38,7 @@ usage() { docker_excl="+d" fi - if [ ${windows} = true ]; + if [ "${windows}" = true ]; then windows_incl="+W" windows_excl="-W" @@ -47,15 +49,14 @@ usage() { if [ $# -ne 0 ]; then - echo > ${msg_path} - echo "$(output_error_msg "${lines[@]}")" >> ${msg_path} - echo >> ${msg_path} - echo >> ${msg_path} + full_msg="In ${args_stage}: +$1" + { echo; output_error_msg "${full_msg}"; echo; } >> "${usage_msg_path}" else - touch ${msg_path} + touch "${usage_msg_path}" fi - cat ${msg_path} - <"${local_oem_file}" + while read -r line do if [ -n "${is_tput}" ]; then echo "$(${is_tput} setab 1)$(${is_tput} setaf 7)${line}$(${is_tput} sgr0)" else - echo "${line}" + echo "$1" fi - done + done <"${local_oem_file}" + rm -f "${local_oem_file}" } check_for_dash_or_end() { - local err_msg; - if [[ -z "$2" || "$2" = "--" ]]; + local_err_msg=""; + if [ -z "$2" ] || [ "$2" = "--" ] then - err_msg=( - "Error: the flag \"$1\" requires a value." - "Value is missing." - ) - usage "${err_msg[@]}" - elif [ "${2:0:1}" = "-" ]; - then - err_msg=( - "Error: either the value for flag \"${1}\" is missing OR" - "the value begins with a \"-\", which is not allowed." - ) - usage "${err_msg[@]}" + local_err_msg="Error: the flag \"$1\" requires a value. +Value is missing." + usage "${local_err_msg}" + else + case "$2" in + -*) + local_err_msg="Error: either the value for flag \"${1}\" is missing OR +the value begins with a \"-\", which is not allowed." + usage "${local_err_msg}" + ;; + esac fi } check_file_writeable_or_creatable() { - local msg_core="\"$2\" given as the value of the \"$1\" flag" - local err_msg; - if [[ -e "$%2" ]]; + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + local_err_msg="" + if [ -e "$%2" ] then - if [[ ! -f "$2" ]]; + if [ ! -f "$2" ] then - err_msg=( - "Error: File ${msg_core} is not a regular file." - "It is either a directory or a device file of some sort." - "Exiting" - ) - output_error_msg "${err_msg[@]}" + local_err_msg="Error: File ${local_msg_core} is not a regular file. +It is either a directory or a device file of some sort. +Exiting" + output_error_msg "${local_err_msg}" exit 1 - elif [[ ! -w "$2" ]]; + elif [ ! -w "$2" ] then - err_msg=( - "Error: File ${msg_core} exists but is not writeable" - "Exiting" - ) - output_error_msg "${err_msg[@]}" + local_err_msg="Error: File ${local_msg_core} exists but is not writeable +Exiting" + output_error_msg "${local_err_msg}" exit 1 fi else - if [[ ! -w "$(dirname -- $2)" ]]; + if [ ! -w "$(dirname -- "$2")" ] then - err_msg=( - "Error: File ${msg_core} cannot be created because" - "its directory either doen't exist or is not writeable." - "Exiting" - ) - output_error_msg "${err_msg[@]}" + local_err_msg="Error: File ${local_msg_core} cannot be created because +its directory either doen't exist or is not writeable. +Exiting" + output_error_msg "${local_err_msg}" exit 1 fi fi } -check_file_readable() { - local msg_core="\"$2\" given as the value of the \"$1\" flag" - if [[ ! -r "$2" ]]; - then - err_msg=( - "Error: File ${msg_core}" - "either doesn't exist or is not readable." - "Exiting" - ) - output_error_msg "${err_msg[@]}" - exit 1 - fi -} - check_dir_writeable_or_creatable() { - local msg_core="\"$2\" given as the value of the \"$1\" flag" - if [[ -e "$2" ]]; + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + local_err_msg="" + if [ -e "$%2" ] then - if [[ ! -d "$2" ]]; + if [ ! -d "$2" ] then - err_msg=( - "Error: Pathname ${msg_core} exists but is not a directory." - "Exiting" - ) - output_error_msg "${err_msg[@]}" + local_err_msg="Error: ${local_msg_core} exists but is not a directory. +Exiting" + output_error_msg "${local_err_msg}" exit 1 - elif [[ ! -w "$2" ]]; + elif [ ! -w "$2" ] then - err_msg=( - "Error: Directory ${msg_core} exists but is not writeable." - "Exiting" - ) - output_error_msg "${err_msg[@]}" + local_err_msg="Error: Directory ${local_msg_core} exists but is not writeable +Exiting" + output_error_msg "${local_err_msg}" exit 1 fi else - if [[ ! -w "$(dirname -- $2)" ]]; + if [ ! -w "$(dirname -- "$2")" ] then - err_msg=( - "Error: Directory ${msg_core} cannot be created because" - "its parent directory either doesn't exist or is not writeable." - "Exiting" - ) - output_error_msg "${err_msg[@]}" + local_err_msg="Error: Directory ${local_msg_core} cannot be created because +its directory either doesn't exist or is not writeable. +Exiting" + output_error_msg "${local_err_msg}" exit 1 fi fi } +check_file_readable() { + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + if [ ! -r "$2" ] + then + local_err_msg="Error: File ${local_msg_core} +either doesn't exist or is not readable. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi +} + +check_dir_exists() { + local_msg_core="\"$2\" given as the value of the \"$1\" flag" + if [ -e "$2" ] + then + if [ ! -d "$2" ] + then + local_err_msg="Error: Pathname ${local_msg_core} exists but is not a directory. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + elif [ ! -r "$2" ] + then + local_err_msg="Error: Directory ${local_msg_core} exists but is not readable. +Exiting" + output_error_msg "${local_err_msg}" + exit 1 + fi + fi +} + +parse_nethub_data() { + nh_host="" + nh_port="" + nh_mac="" + nh_debug="" + # + x="${1%:}:" + nh_host="${x%%:*}" + x="${x#"${nh_host}":*}" + nh_port="${x%%:*}" + if [ "${nh_port}" = "${x}" ]; then nh_port=""; return 0; fi + x="${x#"${nh_port}":*}" + nh_mac="${x%%:*}" + if [ "${nh_mac}" = "${x}" ]; then nh_mac=""; return 0; fi + nh_debug="${x#"${nh_mac}":*}" + if [ "${nh_debug}" = "${x}" ]; then nh_debug=""; return 0; fi + nh_debug="${nh_debug%:}" + return 0 +} + diff --git a/scripts/medley/medley_vnc.sh b/scripts/medley/medley_vnc.sh index 6be2a1a1..d6b5f10c 100755 --- a/scripts/medley/medley_vnc.sh +++ b/scripts/medley/medley_vnc.sh @@ -1,3 +1,6 @@ +#!only-to-be-sourced +# shellcheck shell=sh +# shellcheck disable=SC2154,SC2162 ############################################################################### # # medley_vnc.sh - script for running Medley Interlisp on WSL using Xvnc @@ -19,50 +22,41 @@ } find_open_display() { - local ctr=1 - local result=-1 - local locked_pid=0 - while [ ${ctr} -lt 64 ]; + local_ctr=1 + local_result=-1 + while [ ${local_ctr} -lt 64 ]; do - if [ ! -e /tmp/.X${ctr}-lock ]; + if [ ! -e /tmp/.X${local_ctr}-lock ]; then - result=${ctr} + local_result=${local_ctr} break else - locked_pid=$(cat /tmp/.X${ctr}-lock) - ps lax | awk '{print $3}' | grep --quiet ${locked_pid} >/dev/null - if [ $? -eq 1 ]; - then - result=${ctr} - break - else - (( ctr++ )) - fi + local_ctr=$(( local_ctr+1 )) fi done - echo ${result} + echo ${local_result} } find_open_port() { - local ctr=5900 - local result=-1 - while [ ${ctr} -lt 6000 ]; + local_ctr=5900 + local_result=-1 + while [ ${local_ctr} -lt 6000 ]; do - if [[ ${wsl} = true && ${wsl_ver} -eq 1 ]]; + if [ "${wsl}" = true ] && [ "${wsl_ver}" -eq 1 ] then - netstat.exe -a -n | awk '{ print $2 }' | grep -q ":${ctr}\$" + netstat.exe -a -n | awk '{ print $2 }' | grep -q ":${local_ctr}\$" else - ss -a | grep -q "LISTEN.*:${ctr}[^0-9]" + ss -a | grep -q "LISTEN.*:${local_ctr}[^0-9]" fi if [ $? -eq 1 ]; then - result=${ctr} + local_result=${local_ctr} break else - (( ctr++ )) + local_ctr=$(( local_ctr+1 )) fi done - echo ${result} + echo ${local_result} } # @@ -71,9 +65,9 @@ if [ "${use_vnc}" = "true" ]; then win_userprofile="$(cmd.exe /c "/dev/null)" - vnc_dir="$(wslpath ${win_userprofile})/AppData/Local/Interlisp" + vnc_dir="$(wslpath "${win_userprofile}")/AppData/Local/Interlisp" vnc_exe="vncviewer64-1.12.0.exe" - if [[ $(which Xvnc) = "" || $(Xvnc -version |& grep -iq tigervnc; echo $?) -eq 1 ]]; + if [ "$(which Xvnc)" = "" ] || [ "$(Xvnc -version 2>&1 | grep -iq tigervnc; echo $?)" -eq 1 ] then echo "Error: The -v or --vnc flag was set." echo "But it appears that that TigerVNC \(Xvnc\) has not been installed." @@ -86,165 +80,134 @@ then # make sure TigerVNC viewer is in a Windows (not Linux) directory. If its in a Linux directory # there will be a long delay when it starts up - mkdir -p ${vnc_dir} + mkdir -p "${vnc_dir}" cp -p "${IL_DIR}/wsl/${vnc_exe}" "${vnc_dir}/${vnc_exe}" else - echo "TigerVnc viewer is required by the -vnc option but is not installed." - echo -n "Ok to download from SourceForge? [y, Y, n or N, default n] " - read resp - if [ -z ${resp} ]; then resp=n; else resp=${resp:0:1}; fi - if [[ ${resp} = 'n' || ${resp} = 'N' ]]; - then - echo "Ok. You can download the Tiger VNC viewer \(v1.12.0\) .exe yourself and " - echo "place it in ${vnc_dir}/${vnc_exe}. Then retry." - echo "Exiting." - exit 5 - else - pushd "${vnc_dir}" >/dev/null - wget https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe - popd >/dev/null - fi + loop_done=false + while [ "${loop_done}" = "false" ] + do + echo "TigerVnc viewer is required by the -vnc option but is not installed." + echo "Ok to download from SourceForge? [y, Y, n or N, default n] " + read resp + if [ -z "${resp}" ]; then resp=n; fi + case "${resp}" in + n* | N* ) + echo "Ok. You can download the Tiger VNC viewer \(v1.12.0\) .exe yourself and " + echo "place it in ${vnc_dir}/${vnc_exe}. Then retry." + echo "Exiting." + exit 5 + ;; + y* | Y* ) + wget -P "${vnc_dir}" https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe + loop_done=true + ;; + * ) + echo "Answer not one of Y, y, N, or n. Retry." + ;; + esac + done fi fi fi # # Start the log file so we can trace any issues with vnc, etc # - LOG=${LOGINDIR}/logs/medley_${run_id}.log - mkdir -p $(dirname -- ${LOG}) - echo "START" >${LOG} + LOG="${LOGINDIR}/logs/medley_${run_id}.log" + mkdir -p "$(dirname -- "${LOG}")" + echo "START" >"${LOG}" # - # If we're running under docker: - # set the VNC_PORT to the value of the --port flag (or its default value) - # set DISPLAY to :0 # #set -x - if [ "${docker}" = "true" ]; + # are we running in background - used for pretty-fying the echos + case $(ps -o stat= -p $$) in + *+*) bg=false ;; + *) bg=true ;; + esac + # + # find an unused display and an available port + # + #set -x + OPEN_DISPLAY="$(find_open_display)" + if [ "${OPEN_DISPLAY}" -eq -1 ]; then - export VNC_PORT=5900 - export DISPLAY=:0 + echo "Error: cannot find an unused DISPLAY between 1 and 63" + echo "Exiting" + exit 33 else - # are we running in background - used for pretty-fying the echos - case $(ps -o stat= -p $$) in - *+*) bg=false ;; - *) bg=true ;; - esac - # For not docker (i.e., for wsl/vnc) - # find an unused display and an available port - # - #set -x - OPEN_DISPLAY=`find_open_display` - if [ ${OPEN_DISPLAY} -eq -1 ]; - then - echo "Error: cannot find an unused DISPLAY between 1 and 63" - echo "Exiting" - exit 33 - else - if [ ${bg} = true ]; then echo; fi - echo "Using DISPLAY=:${OPEN_DISPLAY}" - fi - export DISPLAY=":${OPEN_DISPLAY}" - export VNC_PORT=`find_open_port` - if [ ${VNC_PORT} -eq -1 ]; - then - echo "Error: cannot find an unused port between 5900 and 5999" - echo "Exiting" - exit 33 - else - echo "Using VNC_PORT=${VNC_PORT}" - fi + if [ "${bg}" = true ]; then echo; fi + echo "Using DISPLAY=:${OPEN_DISPLAY}" + fi + DISPLAY=":${OPEN_DISPLAY}" + export DISPLAY + VNC_PORT="$(find_open_port)" + export VNC_PORT + if [ "${VNC_PORT}" -eq -1 ]; + then + echo "Error: cannot find an unused port between 5900 and 5999" + echo "Exiting" + exit 33 + else + echo "Using VNC_PORT=${VNC_PORT}" fi # # Start the Xvnc server # - mkdir -p ${LOGINDIR}/logs + mkdir -p "${LOGINDIR}"/logs /usr/bin/Xvnc "${DISPLAY}" \ - -rfbport ${VNC_PORT} \ - -geometry "${geometry#-g }" \ + -rfbport "${VNC_PORT}" \ + -geometry "${geometry}" \ -SecurityTypes None \ -NeverShared \ -DisconnectClients=0 \ -desktop "${title}" \ --MaxDisconnectionTime=10 \ - >> ${LOG} 2>&1 & + >> "${LOG}" 2>&1 & - # Leaving pid wait for all but docker, - # which seems to need it. For all others - # it seems like its not needed but we'll have - # to see how it runs on slower/faster machines - # FGH 2023-02-16 - if [ ${docker} = true ]; - then - xvnc_pid="" - end_time=$(expr $(date +%s) + 10) - while [ -z "${xvnc_pid}" ]; - do - if [ $(date +%s) -gt $end_time ]; - then - echo "Xvnc server failed to start." - echo "See log file at ${LOG}" - echo "Exiting" - exit 3 - fi - sleep .125 - xvnc_pid=$(pgrep -f "Xvnc ${DISPLAY}") - done - # echo "XVNC_PID is ${xvnc_pid}" - fi + sleep .5 # - # Run Medley in foreground if docker, else in background + # Run Maiko in background, handing over the pass-on args which are all thats left in the main args array # - tmp_dir=$(if [[ -d /run/shm && ! -h /run/shm ]]; then echo "/run/shm"; else echo "/tmp"; fi) - medley_run=$(mktemp --tmpdir=${tmp_dir} medley-XXXXX) - cat > ${medley_run} <<..EOF - #!/bin/bash - ${MEDLEYDIR}/run-medley -id '${run_id}' ${geometry} ${screensize} ${run_args[@]} \ - 2>&1 | tee -a ${LOG} | grep -v "broken (explicit kill" - if [ -n "\$(pgrep -f "${vnc_exe}.*:${VNC_PORT}")" ]; then vncconfig -disconnect; fi -..EOF - #cat ${medley_run} - chmod +x ${medley_run} - if [ "${docker}" = "true" ]; + { + start_maiko "$@" + if [ -n "$(pgrep -f "${vnc_exe}.*:${VNC_PORT}")" ]; then vncconfig -disconnect; fi + } & + + # + # Start the vncviewer on the windows side + # + + # First give medley time to startup + # sleep .25 + # SLeep appears not to be needed, but faster/slower machines ???? + # FGH 2023-02-08 + + # Then start vnc viewer on Windows side + vncv_loc=$(( OPEN_DISPLAY * 50 )) + start_time=$(date +%s) + "${vnc_dir}"/${vnc_exe} \ + -geometry "+${vncv_loc}+${vncv_loc}" \ + -ReconnectOnError=off \ + −AlertOnFatalError=off \ + "$(ip_addr)":"${VNC_PORT}" \ + >>"${LOG}" 2>&1 & + wait $! + if [ $(( $(date +%s) - start_time )) -lt 5 ] then - ${medley_run}; rm ${medley_run} - else - (${medley_run}; rm ${medley_run}) & - # - # If not docker (i.e., if wsl/vnc), start the vncviewer on the windows side - # - - # First give medley time to startup - # sleep .25 - # SLeep appears not to be needed, but faster/slower machines ???? - # FGH 2023-02-08 - - # Then start vnc viewer on Windows side - start_time=$(date +%s) - ${vnc_dir}/${vnc_exe} \ - -geometry "+50+50" \ - -ReconnectOnError=off \ - −AlertOnFatalError=off \ - $(ip_addr):${VNC_PORT} \ - >>${LOG} 2>&1 & - wait $! - if [ $( expr $(date +%s) - ${start_time} ) -lt 5 ]; + if [ -z "$(pgrep -f "Xvnc ${DISPLAY}")" ] then - if [ -z "$(pgrep -f "Xvnc ${DISPLAY}")" ]; - then - echo "Xvnc server failed to start." - echo "See log file at ${LOG}" - echo "Exiting" - exit 3 - else - echo "VNC viewer failed to start."; - echo "See log file at ${LOG}"; - echo "Exiting" ; - exit 4; - fi + echo "Xvnc server failed to start." + echo "See log file at ${LOG}" + echo "Exiting" + exit 3 + else + echo "VNC viewer failed to start."; + echo "See log file at ${LOG}"; + echo "Exiting" ; + exit 4; fi fi # - # Done, "Go back" to medley.sh + # Done, "Go back" to medley_run.sh # true