⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{task|Text processing}}
;Task: Given a prompt and a list containing a number of strings of which one is to be selected, create a function that:
- prints a textual menu formatted as an index value followed by its corresponding string for each item in the list;
- prompts the user to enter a number;
- returns the string corresponding to the selected index number.
The function should reject input that is not an integer or is out of range by redisplaying the whole menu before asking again for a number. The function should return an empty string if called with an empty list.
For test purposes use the following four phrases in a list: fee fie huff and puff mirror mirror tick tock
;Note: This task is fashioned after the action of the [http://www.softpanorama.org/Scripting/Shellorama/Control_structures/select_statements.shtml Bash select statement].
=={{header|Ada|}}==
with ada.text_io,Ada.Strings.Unbounded; use ada.text_io, Ada.Strings.Unbounded;
procedure menu is
type menu_strings is array (positive range <>) of Unbounded_String ;
function "+" (s : string) return Unbounded_String is (To_Unbounded_String (s));
function choice (m : menu_strings; prompt : string) return string is
begin
if m'length > 0 then
loop
put_line (prompt);
for i in m'range loop
put_line (i'img &") " & To_String (m(i)));
end loop;
begin
return To_String (m(positive'value (get_line)));
exception when others => put_line ("Try again !");
end;
end loop;
end if;
return "";
end choice;
begin
put_line ("You chose " &
choice ((+"fee fie",+"huff and puff",+"mirror mirror",+"tick tock"),"Enter your choice "));
end menu;
ALGOL 68
{{trans|C}}
{{works with|ALGOL 68|Revision 1 - no extensions to language used}}
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}} {{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''}}
PROC menu select := (FLEX[]STRING items, UNION(STRING, VOID) prompt)STRING:
(
INT choice;
IF LWB items <= UPB items THEN
WHILE
FOR i FROM LWB items TO UPB items DO
printf(($g(0)") "gl$, i, items[i]))
OD;
CASE prompt IN
(STRING prompt):printf(($g" "$, prompt)),
(VOID):printf($"Choice ? "$)
ESAC;
read((choice, new line));
# WHILE # 1 > choice OR choice > UPB items
DO SKIP OD;
items[choice]
ELSE
""
FI
);
test:(
FLEX[0]STRING items := ("fee fie", "huff and puff", "mirror mirror", "tick tock");
STRING prompt := "Which is from the three pigs : ";
printf(($"You chose "g"."l$, menu select(items, prompt)))
)
Output:
1) fee fie
2) huff and puff
3) mirror mirror
4) tick tock
Which is from the three pigs : 2
You chose huff and puff.
AutoHotkey
{{incorrect|AutoHotkey|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}}
GoSub, CreateGUI
return
Submit:
Gui, Submit, NoHide
If Input =
GuiControl,,Output
Else If Input not between 1 and 4
{
Gui, Destroy
Sleep, 500
GoSub, CreateGUI
}
Else {
GuiControlGet, string,,Text%Input%
GuiControl,,Output,% SubStr(string,4)
}
return
CreateGUI:
list = fee fie,huff and puff,mirror mirror,tick tock
Loop, Parse, list, `,
Gui, Add, Text, vText%A_Index%, %A_Index%: %A_LoopField%
Gui, Add, Text, ym, Which is from the three pigs?
Gui, Add, Edit, vInput gSubmit
Gui, Add, Edit, vOutput
Gui, Show
return
GuiClose:
ExitApp
AWK
# syntax: GAWK -f MENU.AWK
BEGIN {
print("you picked:",menu(""))
print("you picked:",menu("fee fie:huff and puff:mirror mirror:tick tock"))
exit(0)
}
function menu(str, ans,arr,i,n) {
if (str == "") {
return
}
n = split(str,arr,":")
while (1) {
print("")
for (i=1; i<=n; i++) {
printf("%d - %s\n",i,arr[i])
}
printf("? ")
getline ans
if (ans in arr) {
return(arr[ans])
}
print("invalid choice")
}
}
Axe
{{incorrect|Axe|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}} In Axe, static data (such as strings) is laid out sequentially in memory. So the H in "HUFF" is the byte after the null terminator for "FIE". However, null terminators are only added to strings when they are stored with the store symbol →. strGet returns a pointer to the start of the nth null-terminated string in the data, which is why the strings must be laid out in memory correctly.
"FEE FIE"→Str1
"HUFF AND PUFF"→Str2
"MIRROR MIRROR"→Str3
"TICK TOCK"→Str4
For(I,1,4)
Disp I▶Hex+3,":",strGet(Str1,I-1),i
End
Disp "NUMBER? "
input→A
{A}-'0'→N
If N<1 or N>4
Disp "BAD NUMBER",i
Return
End
Disp strGet(Str1,N-1),i
BASIC
{{works with|QuickBasic|4.5}}
function sel$(choices$(), prompt$)
if ubound(choices$) - lbound(choices$) = 0 then sel$ = ""
ret$ = ""
do
for i = lbound(choices$) to ubound(choices$)
print i; ": "; choices$(i)
next i
input ;prompt$, index
if index <= ubound(choices$) and index >= lbound(choices$) then ret$ = choices$(index)
while ret$ = ""
sel$ = ret$
end function
@echo off & setlocal enabledelayedexpansion
set "menuChoices="fee fie","huff and puff","mirror mirror","tick tock""
call :menu
pause>nul & exit
:menu
if defined menuChoices (
set "counter=0" & for %%a in (%menuChoices%) do (
set /a "counter+=1"
set "currentMenuChoice=%%a"
set option[!counter!]=!currentMenuChoice:"=!
)
)
:tryagain
cls&echo.
for /l %%a in (1,1,%counter%) do echo %%a^) !option[%%a]!
echo.
set /p "input=Choice 1-%counter%: "
echo.
for /l %%a in (1,1,%counter%) do (
if !input! equ %%a echo You chose [ %%a^) !option[%%a]! ] & goto :EOF
)
echo.
echo.Invalid Input. Please try again...
pause
goto :tryagain
Batch File
@echo off
call:menu "fee fie" "huff and puff" "mirror mirror" "tick tock"
pause>nul
exit /b
:menu
cls
setlocal enabledelayedexpansion
set count=0
set reset=endlocal ^& goto menu
:menuloop
for %%i in (%*) do (
set /a count+=1
set string[!count!]=%%~i
echo string[!count!] = %%~i
)
echo.
set /p choice=^>
if "%choice%"=="" %reset%
set "isNum="
for /f "delims=0123456789" %%i in ("%choice%") do set isNum=%%i
if defined isNum %reset%
if %choice% gtr %count% %reset%
echo.!string[%choice%]!
goto:eof
BBC BASIC
DIM list$(4)
list$() = "fee fie", "huff and puff", "mirror mirror", "tick tock"
selected$ = FNmenu(list$(), "Please make a selection: ")
PRINT selected$
END
DEF FNmenu(list$(), prompt$)
LOCAL index%, select$
IF SUM(list$()) = "" THEN = ""
REPEAT
CLS
FOR index% = 0 TO DIM(list$() ,1)
IF list$(index%)<>"" PRINT ; index% ":", list$(index%)
NEXT
PRINT prompt$ ;
INPUT "" select$
index% = VAL(select$)
IF select$<>STR$(index%) index% = -1
IF index%>=0 IF index%<=DIM(list$() ,1) IF list$(index%)="" index% = -1
UNTIL index%>=0 AND index%<=DIM(list$(), 1)
= list$(index%)
Empty entries in the list are not offered as options, nor accepted as a selection.
Brat
menu = { prompt, choices |
true? choices.empty?
{ "" }
{
choices.each_with_index { c, i |
p "#{i}. #{c}"
}
selection = ask prompt
true? selection.numeric?
{ selection = selection.to_i
true? selection < 0 || { selection >= choices.length }
{ p "Selection is out of range"; menu prompt, choices }
{ choices[selection] }
}
{ p "Selection must be a number"; menu prompt, choices }
}
}
p menu "Selection: " ["fee fie" "huff and puff" "mirror mirror" "tick tock"]
C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *menu_select(const char *const *items, const char *prompt);
int
main(void)
{
const char *items[] = {"fee fie", "huff and puff", "mirror mirror", "tick tock", NULL};
const char *prompt = "Which is from the three pigs?";
printf("You chose %s.\n", menu_select(items, prompt));
return EXIT_SUCCESS;
}
const char *
menu_select(const char *const *items, const char *prompt)
{
char buf[BUFSIZ];
int i;
int choice;
int choice_max;
if (items == NULL)
return NULL;
do {
for (i = 0; items[i] != NULL; i++) {
printf("%d) %s\n", i + 1, items[i]);
}
choice_max = i;
if (prompt != NULL)
printf("%s ", prompt);
else
printf("Choice? ");
if (fgets(buf, sizeof(buf), stdin) != NULL) {
choice = atoi(buf);
}
} while (1 > choice || choice > choice_max);
return items[choice - 1];
}
C++
#include <iostream>
#include <string>
#include <vector>
void print_menu(const std::vector<std::string>& terms)
{
for (size_t i = 0; i < terms.size(); i++) {
std::cout << i + 1 << ") " << terms[i] << '\n';
}
}
int parse_entry(const std::string& entry, int max_number)
{
int number = std::stoi(entry);
if (number < 1 || number > max_number) {
throw std::invalid_argument("");
}
return number;
}
std::string data_entry(const std::string& prompt, const std::vector<std::string>& terms)
{
if (terms.empty()) {
return "";
}
int choice;
while (true) {
print_menu(terms);
std::cout << prompt;
std::string entry;
std::cin >> entry;
try {
choice = parse_entry(entry, terms.size());
return terms[choice - 1];
} catch (std::invalid_argument&) {
// std::cout << "Not a valid menu entry!" << std::endl;
}
}
}
int main()
{
std::vector<std::string> terms = {"fee fie", "huff and puff", "mirror mirror", "tick tock"};
std::cout << "You chose: " << data_entry("> ", terms) << std::endl;
}
C#
using System;
using System.Collections.Generic;
public class Menu
{
static void Main(string[] args)
{
List<string> menu_items = new List<string>() { "fee fie", "huff and puff", "mirror mirror", "tick tock" };
//List<string> menu_items = new List<string>();
Console.WriteLine(PrintMenu(menu_items));
Console.ReadLine();
}
private static string PrintMenu(List<string> items)
{
if (items.Count == 0)
return "";
string input = "";
int i = -1;
do
{
for (int j = 0; j < items.Count; j++)
Console.WriteLine("{0}) {1}", j, items[j]);
Console.WriteLine("What number?");
input = Console.ReadLine();
} while (!int.TryParse(input, out i) || i >= items.Count || i < 0);
return items[i];
}
}
Ceylon
"Run the module `menu`."
shared void run() {
value selection = menu("fee fie", "huff And puff", "mirror mirror", "tick tock");
print(selection);
}
String menu(String* strings) {
if(strings.empty) {
return "";
}
value entries = map(zipEntries(1..strings.size, strings));
while(true) {
for(index->string in entries) {
print("``index``) ``string``");
}
process.write("> ");
value input = process.readLine();
if(exists input, exists int = parseInteger(input), exists string = entries[int]) {
return string;
}
}
}
Clojure
(defn menu [prompt choices]
(if (empty? choices)
""
(let [menutxt (apply str (interleave
(iterate inc 1)
(map #(str \space % \newline) choices)))]
(println menutxt)
(print prompt)
(flush)
(let [index (read-string (read-line))]
; verify
(if (or (not (integer? index))
(> index (count choices))
(< index 1))
; try again
(recur prompt choices)
; ok
(nth choices (dec index)))))))
(println "You chose: "
(menu "Which is from the three pigs: "
["fee fie" "huff and puff" "mirror mirror" "tick tock"]))
COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. Test-Prompt-Menu.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Num-Options USAGE UNSIGNED-INT VALUE 4.
01 Example-Menu.
03 Example-Options-Data.
05 FILLER PIC X(30) VALUE "fee fie".
05 FILLER PIC X(30) VALUE "huff and puff".
05 FILLER PIC X(30) VALUE "mirror mirror".
05 FILLER PIC X(30) VALUE "tick tock".
03 Example-Options-Values REDEFINES Example-Options-Data.
05 Example-Options PIC X(30) OCCURS 4 TIMES.
01 Chosen-Option PIC X(30).
PROCEDURE DIVISION.
CALL "Prompt-Menu" USING BY CONTENT Num-Options
BY CONTENT Example-Menu
BY REFERENCE Chosen-Option
DISPLAY "You chose: " Chosen-Option
GOBACK
.
END PROGRAM Test-Prompt-Menu.
IDENTIFICATION DIVISION.
PROGRAM-ID. Prompt-Menu.
DATA DIVISION.
LOCAL-STORAGE SECTION.
01 User-Input USAGE UNSIGNED-INT.
01 Input-Flag PIC X.
88 Valid-Input VALUE "Y".
01 Options-Index USAGE UNSIGNED-INT.
01 Index-Display PIC Z(10).
LINKAGE SECTION.
01 Num-Options USAGE UNSIGNED-INT.
01 Menu-Options.
03 Options-Table PIC X(30) OCCURS 0 TO 10000000 TIMES
DEPENDING ON Num-Options.
01 Chosen-Option PIC X(30).
PROCEDURE DIVISION USING Num-Options Menu-Options Chosen-Option.
Main.
IF Num-Options = 0
MOVE SPACES TO Chosen-Option
GOBACK
END-IF
PERFORM UNTIL Valid-Input
PERFORM Display-Menu-Options
DISPLAY "Choose an option: " WITH NO ADVANCING
ACCEPT User-Input
PERFORM Validate-Input
END-PERFORM
MOVE Options-Table (User-Input) TO Chosen-Option
GOBACK
.
Display-Menu-Options.
PERFORM VARYING Options-Index FROM 1 BY 1
UNTIL Num-Options < Options-Index
MOVE Options-Index TO Index-Display
DISPLAY
Index-Display ". " Options-Table (Options-Index)
END-DISPLAY
END-PERFORM
.
Validate-Input.
IF User-Input = 0 OR > Num-Options
DISPLAY "Invalid input."
ELSE
SET Valid-Input TO TRUE
END-IF
.
END PROGRAM Prompt-Menu.
Common Lisp
(defun select (prompt choices)
(if (null choices)
""
(do (n)
((and n (<= 0 n (1- (length choices))))
(nth n choices))
(format t "~&~a~%" prompt)
(loop for n from 0
for c in choices
do (format t " ~d) ~a~%" n c))
(force-output)
(setf n (parse-integer (read-line *standard-input* nil)
:junk-allowed t)))))
D
import std.stdio, std.conv, std.string, std.array, std.typecons;
string menuSelect(in string[] entries) {
static Nullable!(int, -1) validChoice(in string input,
in int nEntries)
pure nothrow {
try {
immutable n = input.to!int;
return typeof(return)((n >= 0 && n <= nEntries) ? n : -1);
} catch (Exception e) // Very generic
return typeof(return)(-1); // Not valid.
}
if (entries.empty)
return "";
while (true) {
"Choose one:".writeln;
foreach (immutable i, const entry; entries)
writefln(" %d) %s", i, entry);
"> ".write;
immutable input = readln.chomp;
immutable choice = validChoice(input, entries.length - 1);
if (choice.isNull)
"Wrong choice.".writeln;
else
return entries[choice]; // We have a valid choice.
}
}
void main() {
immutable items = ["fee fie", "huff and puff",
"mirror mirror", "tick tock"];
writeln("You chose '", items.menuSelect, "'.");
}
{{out}}
Choose one:
0) fee fie
1) huff and puff
2) mirror mirror
3) tick tock
> 2
You chose 'mirror mirror'.
Elixir
defmodule Menu do
def select(_, []), do: ""
def select(prompt, items) do
IO.puts ""
Enum.with_index(items) |> Enum.each(fn {item,i} -> IO.puts " #{i}. #{item}" end)
answer = IO.gets("#{prompt}: ") |> String.strip
case Integer.parse(answer) do
{num, ""} when num in 0..length(items)-1 -> Enum.at(items, num)
_ -> select(prompt, items)
end
end
end
# test empty list
response = Menu.select("Which is empty", [])
IO.puts "empty list returns: #{inspect response}"
# "real" test
items = ["fee fie", "huff and puff", "mirror mirror", "tick tock"]
response = Menu.select("Which is from the three pigs", items)
IO.puts "you chose: #{inspect response}"
{{out}}
empty list returns: ""
0. fee fie
1. huff and puff
2. mirror mirror
3. tick tock
Which is from the three pigs: 4
0. fee fie
1. huff and puff
2. mirror mirror
3. tick tock
Which is from the three pigs: 3
you chose: "tick tock"
ERRE
PROCEDURE Selection(choices$[],prompt$->sel$)
IF UBOUND(choices$,1)-LBOUND(choices$,1)=0 THEN
sel$=""
EXIT PROCEDURE
END IF
ret$=""
REPEAT
FOR i=LBOUND(choices$,1) TO UBOUND(choices$,1) DO
PRINT(i;": ";choices$[i])
END FOR
PRINT(prompt$;)
INPUT(index)
IF index<=UBOUND(choices$,1) AND index>=LBOUND(choices$,1) THEN ret$=choices$[index] END IF
UNTIL ret$<>""
sel$=ret$
END PROCEDURE
Euphoria
include get.e
function menu_select(sequence items, object prompt)
if length(items) = 0 then
return ""
else
for i = 1 to length(items) do
printf(1,"%d) %s\n",{i,items[i]})
end for
if atom(prompt) then
prompt = "Choice?"
end if
return items[prompt_number(prompt,{1,length(items)})]
end if
end function
constant items = {"fee fie", "huff and puff", "mirror mirror", "tick tock"}
constant prompt = "Which is from the three pigs? "
printf(1,"You chose %s.\n",{menu_select(items,prompt)})
Factor
USING: formatting io kernel math math.parser sequences ;
: print-menu ( seq -- )
[ 1 + swap "%d - %s\n" printf ] each-index
"Your choice? " write flush ;
: (select) ( seq -- result )
dup print-menu readln string>number dup integer? [
drop 1 - swap 2dup bounds-check?
[ nth ] [ nip (select) ] if
] [ drop (select) ] if* ;
: select ( seq -- result ) [ "" ] [ (select) ] if-empty ;
Example usage:
( scratchpad ) { "fee fie" "huff and puff" "mirror mirror" "tick tock" } select
1 - fee fie
2 - huff and puff
3 - mirror mirror
4 - tick tock
Your choice? 1
--- Data stack:
"fee fie"
Fantom
{{incorrect|Fantom|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}}
class Main
{
static Void displayList (Str[] items)
{
items.each |Str item, Int index|
{
echo ("$index: $item")
}
}
public static Str getChoice (Str[] items)
{
selection := -1
while (selection == -1)
{
displayList (items)
Env.cur.out.print ("Select: ").flush
input := Int.fromStr(Env.cur.in.readLine, 10, false)
if (input != null)
{
if (input >= 0 && input < items.size)
{
selection = input
}
}
echo ("Try again")
}
return items[selection]
}
public static Void main ()
{
choice := getChoice (["fee fie", "huff and puff", "mirror mirror", "tick tock"])
echo ("You chose: $choice")
}
}
Forth
Idiomatic Forth
Out of the box Forth does not have lists. This version uses strings and a vector table, which arguably is more how one would do this task in Forth. It returns a nil string if a nil string is given otherwise the input string becomes the title of the menu.
\ Rosetta Code Menu Idiomatic Forth
\ vector table compiler
: CASE: ( -- ) CREATE ;
: | ( -- <text>) ' , ; IMMEDIATE
: ;CASE ( -- ) DOES> SWAP CELLS + @ EXECUTE ;
: NIL ( -- addr len) S" " ;
: FEE ( -- addr len) S" fee fie" ;
: HUFF ( -- addr len) S" huff and puff" ;
: MIRROR ( -- addr len) S" mirror mirror" ;
: TICKTOCK ( -- addr len) S" tick tock" ;
CASE: SELECT ( n -- addr len)
| NIL | FEE | HUFF | MIRROR | TICKTOCK
;CASE
CHAR 1 CONSTANT '1'
CHAR 4 CONSTANT '4'
: BETWEEN ( n low hi -- ?) 1+ WITHIN ;
: MENU ( addr len -- addr len )
DUP 0=
IF
2DROP NIL EXIT
ELSE
BEGIN
CR
CR 2DUP 3 SPACES TYPE
CR ." 1 " 1 SELECT TYPE
CR ." 2 " 2 SELECT TYPE
CR ." 3 " 3 SELECT TYPE
CR ." 4 " 4 SELECT TYPE
CR ." Choice: " KEY DUP EMIT
DUP '1' '4' BETWEEN 0=
WHILE
DROP
REPEAT
-ROT 2DROP \ drop input string
CR [CHAR] 0 - SELECT
THEN
;
If there must be lists
Here we extend Forth to support simple lists and complete the task using the language extensions.
\ Rosetta Menu task with Simple lists in Forth
: STRING, ( caddr len -- ) HERE OVER CHAR+ ALLOT PLACE ;
: " ( -- ) [CHAR] " PARSE STRING, ;
: { ( -- ) ALIGN 0 C, ;
: } ( -- ) { ;
: {NEXT} ( str -- next_str) COUNT + ;
: {NTH} ( n array_addr -- str) SWAP 0 DO {NEXT} LOOP ;
: {LEN} ( array_addr -- ) \ count strings in a list
0 >R \ Counter on Rstack
{NEXT} \ skip 1st empty string
BEGIN
{NEXT} DUP C@ \ Fetch length byte
WHILE \ While true
R> 1+ >R \ Inc. counter
REPEAT
DROP
R> ; \ return counter to data stack
: {TYPE} ( $ -- ) COUNT TYPE ;
: '"' ( -- ) [CHAR] " EMIT ;
: {""} ( $ -- ) '"' SPACE {TYPE} '"' SPACE ;
: }PRINT ( n array -- ) {NTH} {TYPE} ;
\
### == TASK BEGINS ==
CREATE GOODLIST
{ " fee fie"
" huff and puff"
" mirror mirror"
" tick tock" }
CREATE NIL { }
CHAR 1 CONSTANT '1'
CHAR 4 CONSTANT '4'
CHAR 0 CONSTANT '0'
: BETWEEN ( n low hi -- ?) 1+ WITHIN ;
: .MENULN ( n -- n) DUP '0' + EMIT SPACE OVER }PRINT ;
: MENU ( list -- string )
DUP {LEN} 0=
IF
DROP NIL
ELSE
BEGIN
CR
CR 1 .MENULN
CR 2 .MENULN
CR 3 .MENULN
CR 4 .MENULN
CR ." Choice: " KEY DUP EMIT
DUP '1' '4' BETWEEN
0= WHILE
DROP
REPEAT
[CHAR] 0 -
CR SWAP {NTH}
THEN
;
Test at the gForth console
GOODLIST MENU 1 fee fie 2 huff and puff 3 mirror mirror 4 tick tock Choice: 0 1 fee fie 2 huff and puff 3 mirror mirror 4 tick tock Choice: Q 1 fee fie 2 huff and puff 3 mirror mirror 4 tick tock Choice: 2 ok {TYPE} huff and puff ok ok NIL MENU ok {TYPE} ok## Fortran Please find the build instructions in the comments at the start of the FORTRAN 2008 source. Compiler: gfortran from the GNU compiler collection. Command interpreter: bash. ```FORTRAN !a=./f && make $a && OMP_NUM_THREADS=2 $a !gfortran -std=f2008 -Wall -fopenmp -ffree-form -fall-intrinsics -fimplicit-none f.f08 -o f module menu public :: selector contains function selector(title,options) result(choice) character(len=*),intent(in) :: title character(len=*),dimension(:),intent(in) :: options character(len=len(options)) :: choice integer :: i,ichoose,ios,n choice = "" n = size(options) if (n > 0) then do print "(a)",title print "(i8,"", "",a)",(i,options(i),i=1,n) read (*,fmt="(i8)",iostat=ios) ichoose if (ios == -1) exit ! EOF error if (ios /= 0) cycle ! other error if (ichoose < 1) cycle if (ichoose > n) cycle ! out-of-bounds choice = options(ichoose) exit end do end if end function selector end module menu program menu_demo use menu character(len=14),dimension(:),allocatable :: zero_items,fairytale character(len=len(zero_items)) :: s !! empty list demo allocate(zero_items(0)) print "(a)","input items:",zero_items s = selector('Choose from the empty list',zero_items) print "(a)","returned:",s if (s == "") print "(a)","(an empty string)" !! Fairy tale demo allocate(fairytale(4)) fairytale = (/'fee fie ','huff and puff ', & 'mirror mirror ','tick tock '/) print "(a)","input items:",fairytale s = selector('Choose a fairy tale',fairytale) print "(a)","returned: ",s if (s == "") print "(a)","(an empty string)" end program menu_demo ``` =={{header|F Sharp|F#}}== ```fsharp open System let rec menuChoice (options : string list) prompt = if options = [] then "" else for i = 0 to options.Length - 1 do printfn "%d. %s" (i + 1) options.[i] printf "%s" prompt let input = Int32.TryParse(Console.ReadLine()) match input with | true, x when 1 <= x && x <= options.Length -> options.[x - 1] | _, _ -> menuChoice options prompt [
choose
that nearly conforms to this task. The input list is altered so that the choice can be returned, and the empty list case is handled.
```min
(
:prompt =list
(list bool)
(list (' dup append) map prompt choose)
("") if
) :menu
("fee fie" "huff and puff" "mirror mirror" "tick tock")
"Enter an option" menu
"You chose: " print! puts!
```
{{out}}
```txt
Enter an option
1 - fee fie
2 - huff and puff
3 - mirror mirror
4 - tick tock
Enter your choice (1 - 4): 5
Invalid choice.
1 - fee fie
2 - huff and puff
3 - mirror mirror
4 - tick tock
Enter your choice (1 - 4): 1
You chose: fee fie
```
=={{header|Modula-2}}==
{{incorrect|Modula-2|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}}
```modula2
MODULE Menu;
FROM InOut IMPORT WriteString, WriteCard, WriteLn, ReadCard;
CONST StringLength = 100;
MenuSize = 4;
TYPE String = ARRAY[0..StringLength-1] OF CHAR;
VAR menu : ARRAY[0..MenuSize] OF String;
selection, index : CARDINAL;
BEGIN
menu[1] := "fee fie";
menu[2] := "huff and puff";
menu[3] := "mirror mirror";
menu[4] := "tick tock";
FOR index := 1 TO HIGH(menu) DO
WriteString("[");
WriteCard( index,1);
WriteString( "] ");
WriteString( menu[index]);
WriteLn;
END;(*of FOR*)
WriteString("Choose what you want : ");
ReadCard(selection);
IF (selection <= HIGH(menu)) AND (selection > 0) THEN
WriteString("You have chosen: ");
WriteString( menu[selection]);
WriteLn;
ELSE
WriteString("Selection is out of range!");
WriteLn;
END (*of IF*)
END Menu.
```
## MUMPS
```MUMPS
MENU(STRINGS,SEP)
;http://rosettacode.org/wiki/Menu
NEW I,A,MAX
;I is a loop variable
;A is the string read in from the user
;MAX is the number of substrings in the STRINGS list
;SET STRINGS="fee fie^huff and puff^mirror mirror^tick tock"
SET MAX=$LENGTH(STRINGS,SEP)
QUIT:MAX=0 ""
WRITEMENU
FOR I=1:1:MAX WRITE I,": ",$PIECE(STRINGS,SEP,I),!
READ:30 !,"Choose a string by its index: ",A,!
IF (A<1)!(A>MAX)!(A\1'=A) GOTO WRITEMENU
KILL I,MAX
QUIT $PIECE(STRINGS,SEP,A)
```
Usage:
```txt
USER>W !,$$MENU^ROSETTA("fee fie^huff and puff^mirror mirror^tick tock","^")
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Choose a string by its index: 3
mirror mirror
USER>W !,$$MENU^ROSETTA("fee fie^huff and puff^mirror mirror^tick tock","^")
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Choose a string by its index: 5
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Choose a string by its index: A
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Choose a string by its index: 0
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Choose a string by its index: 1
fee fie
```
## Nim
{{trans|Python}}
```nim
import strutils, rdstdin
proc menu(xs) =
for i,x in xs: echo " ",i,") ",x
proc ok(reply, count): bool =
try:
let n = parseInt(reply)
return 0 <= n and n < count
except: return false
proc selector(xs, prompt): string =
if xs.len == 0: return ""
var reply = "-1"
while not ok(reply, xs.len):
menu(xs)
reply = readLineFromStdin(prompt).strip()
return xs[parseInt(reply)]
const xs = ["fee fie", "huff and puff", "mirror mirror", "tick tock"]
let item = selector(xs, "Which is from the three pigs: ")
echo "You chose: ", item
```
Output:
```txt
0) fee fie
1) huff and puff
2) mirror mirror
3) tick tock
Which is from the three pigs: foo
0) fee fie
1) huff and puff
2) mirror mirror
3) tick tock
Which is from the three pigs: 4
0) fee fie
1) huff and puff
2) mirror mirror
3) tick tock
Which is from the three pigs: 2
You chose: mirror mirror
```
## OCaml
```ocaml
let select ?(prompt="Choice? ") = function
| [] -> ""
| choices ->
let rec menu () =
List.iteri (Printf.printf "%d: %s\n") choices;
print_string prompt;
try List.nth choices (read_int ())
with _ -> menu ()
in menu ()
```
Example use in the REPL:
```ocaml
# select ["fee fie"; "huff and puff"; "mirror mirror"; "tick tock"];;
0: fee fie
1: huff and puff
2: mirror mirror
3: tick tock
Choice? 2
- : string = "mirror mirror"
```
## OpenEdge/Progress
```progress
FUNCTION bashMenu RETURNS CHAR(
i_c AS CHAR
):
DEF VAR ii AS INT.
DEF VAR hfr AS HANDLE.
DEF VAR hmenu AS HANDLE EXTENT.
DEF VAR ikey AS INT.
DEF VAR ireturn AS INT INITIAL ?.
EXTENT( hmenu ) = NUM-ENTRIES( i_c ).
CREATE FRAME hfr ASSIGN
WIDTH = 80
HEIGHT = NUM-ENTRIES( i_c )
PARENT = CURRENT-WINDOW
VISIBLE = TRUE
.
DO ii = 1 TO NUM-ENTRIES( i_c ):
CREATE TEXT hmenu ASSIGN
FRAME = hfr
FORMAT = "x(79)"
SCREEN-VALUE = SUBSTITUTE( "&1. &2", ii, ENTRY( ii, i_c ) )
ROW = ii
VISIBLE = TRUE
.
END.
IF i_c = "" THEN
ireturn = 1.
DO WHILE ireturn = ?:
READKEY.
ikey = INTEGER( CHR( LASTKEY ) ) NO-ERROR.
IF ikey >= 1 AND ikey <= NUM-ENTRIES( i_c ) THEN
ireturn = ikey.
END.
RETURN ENTRY( ireturn, i_c ).
END FUNCTION.
MESSAGE
bashMenu( "fee fie,huff and puff,mirror mirror,tick tock" )
VIEW-AS ALERT-BOX.
```
## Oz
```oz
declare
fun {Select Prompt Items}
case Items of nil then ""
else
for
Item in Items
Index in 1..{Length Items}
do
{System.showInfo Index#") "#Item}
end
{System.printInfo Prompt}
try
{Nth Items {ReadInt}}
catch _ then
{Select Prompt Items}
end
end
end
fun {ReadInt}
class TextFile from Open.file Open.text end
StdIo = {New TextFile init(name:stdin)}
in
{String.toInt {StdIo getS($)}}
end
Item = {Select "Which is from the three pigs: "
["fee fie" "huff and puff" "mirror mirror" "tick tock"]}
in
{System.showInfo "You chose: "#Item}
```
## PARI/GP
{{incorrect|PARI/GP|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}}
```parigp
choose(v)=my(n);for(i=1,#v,print(i". "v[i]));while(type(n=input())!="t_INT"|n>#v|n<1,);v[n]
choose(["fee fie","huff and puff","mirror mirror","tick tock"])
```
## Pascal
{{works with|Free_Pascal}}
Tested with Free Pascal 2.6.4 (arm).
```pascal
program Menu;
{$ASSERTIONS ON}
uses
objects;
var
MenuItems :PUnSortedStrCollection;
selected :string;
Function SelectMenuItem(MenuItems :PUnSortedStrCollection):string;
var
i, idx :integer;
code :word;
choice :string;
begin
// Return empty string if the collection is empty.
if MenuItems^.Count = 0 then
begin
SelectMenuItem := '';
Exit;
end;
repeat
for i:=0 to MenuItems^.Count-1 do
begin
writeln(i+1:2, ') ', PString(MenuItems^.At(i))^);
end;
write('Make your choice: ');
readln(choice);
// Try to convert choice to an integer.
// Code contains 0 if this was successful.
val(choice, idx, code)
until (code=0) and (idx>0) and (idx<=MenuItems^.Count);
// Return the selected element.
SelectMenuItem := PString(MenuItems^.At(idx-1))^;
end;
begin
// Create an unsorted string collection for the menu items.
MenuItems := new(PUnSortedStrCollection, Init(10, 10));
// Add some menu items to the collection.
MenuItems^.Insert(NewStr('fee fie'));
MenuItems^.Insert(NewStr('huff and puff'));
MenuItems^.Insert(NewStr('mirror mirror'));
MenuItems^.Insert(NewStr('tick tock'));
// Display the menu and get user input.
selected := SelectMenuItem(MenuItems);
writeln('You chose: ', selected);
dispose(MenuItems, Done);
// Test function with an empty collection.
MenuItems := new(PUnSortedStrCollection, Init(10, 10));
selected := SelectMenuItem(MenuItems);
// Assert that the function returns an empty string.
assert(selected = '', 'Assertion failed: the function did not return an empty string.');
dispose(MenuItems, Done);
end.
```
{{out}}
```txt
$ bin/menu
1) fee fie
2) huff and puff
3) mirror mirror
4) tick tock
Make your choice: abc
1) fee fie
2) huff and puff
3) mirror mirror
4) tick tock
Make your choice: 99
1) fee fie
2) huff and puff
3) mirror mirror
4) tick tock
Make your choice: 3
You chose: mirror mirror
```
## Perl
```perl
sub menu
{
my ($prompt,@array) = @_;
return '' unless @array;
print " $_: $array[$_]\n" for(0..$#array);
print $prompt;
$n = <>;
return $array[$n] if $n =~ /^\d+$/ and defined $array[$n];
return &menu($prompt,@array);
}
@a = ('fee fie', 'huff and puff', 'mirror mirror', 'tick tock');
$prompt = 'Which is from the three pigs: ';
$a = &menu($prompt,@a);
print "You chose: $a\n";
```
## Perl 6
```perl6
sub menu ( $prompt, @items ) {
return '' unless @items.elems;
repeat until my $selection ~~ /^ \d+ $/ && @items[--$selection] {
my $i = 1;
say " {$i++}) $_" for @items;
$selection = prompt $prompt;
}
return @items[$selection];
}
my @choices = 'fee fie', 'huff and puff', 'mirror mirror', 'tick tock';
my $prompt = 'Enter the number corresponding to your selection: ';
my $answer = menu( $prompt, [] );
say "You chose: $answer" if $answer.chars;
$answer = menu( $prompt, @choices );
say "You chose: $answer" if $answer.chars;
```
## PL/I
{{incorrect|PL/I|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}}
```PL/I
test: proc options (main);
declare menu(4) character(100) varying static initial (
'fee fie', 'huff and puff', 'mirror mirror', 'tick tock');
declare (i, k) fixed binary;
do i = lbound(menu,1) to hbound(menu,1);
put skip edit (trim(i), ': ', menu(i) ) (a);
end;
put skip list ('please choose an item number');
get list (k);
if k >= lbound(menu,1) & k <= hbound(menu,1) then
put skip edit ('you chose ', menu(k)) (a);
else
put skip list ('Could not find your phrase');
end test;
```
## Phix
```Phix
function menu_select(sequence items, object prompt)
sequence res = ""
items = remove_all("",items)
if length(items)!=0 then
while 1 do
for i=1 to length(items) do
printf(1,"%d) %s\n",{i,items[i]})
end for
puts(1,iff(atom(prompt)?"Choice?":prompt))
res = scanf(trim(gets(0)),"%d")
puts(1,"\n")
if length(res)=1 then
integer nres = res[1][1]
if nres>0 and nres<=length(items) then
res = items[nres]
exit
end if
end if
end while
end if
return res
end function
constant items = {"fee fie", "huff and puff", "mirror mirror", "tick tock"}
constant prompt = "Which is from the three pigs? "
string res = menu_select(items,prompt)
printf(1,"You chose %s.\n",{res})
```
## PHP
```php
'fee fie', 'huff and puff', 'mirror mirror', 'tick tock');
for(;;) {
foreach ($allowed as $id => $name) {
echo " $id: $name\n";
}
echo "Which is from the four pigs: ";
$stdin_string = fgets($stdin, 4096);
if (isset($allowed[(int) $stdin_string])) {
echo "You chose: {$allowed[(int) $stdin_string]}\n";
break;
}
}
```
## PicoLisp
```PicoLisp
(de choose (Prompt Items)
(use N
(loop
(for (I . Item) Items
(prinl I ": " Item) )
(prin Prompt " ")
(flush)
(NIL (setq N (in NIL (read))))
(T (>= (length Items) N 1) (prinl (get Items N))) ) ) )
(choose "Which is from the three pigs?"
'("fee fie" "huff and puff" "mirror mirror" "tick tock") )
```
{{out}}
```txt
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Which is from the three pigs? q
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Which is from the three pigs? 5
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
Which is from the three pigs? 2
huff and puff
```
## PowerShell
{{incorrect|PowerShell|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine].}}
```PowerShell
function Select-TextItem
{
<#
.SYNOPSIS
Prints a textual menu formatted as an index value followed by its corresponding string for each object in the list.
.DESCRIPTION
Prints a textual menu formatted as an index value followed by its corresponding string for each object in the list;
Prompts the user to enter a number;
Returns an object corresponding to the selected index number.
.PARAMETER InputObject
An array of objects.
.PARAMETER Prompt
The menu prompt string.
.EXAMPLE
“fee fie”, “huff and puff”, “mirror mirror”, “tick tock” | Select-TextItem
.EXAMPLE
“huff and puff”, “fee fie”, “tick tock”, “mirror mirror” | Sort-Object | Select-TextItem -Prompt "Select a string"
.EXAMPLE
Select-TextItem -InputObject (Get-Process)
.EXAMPLE
(Get-Process | Where-Object {$_.Name -match "notepad"}) | Select-TextItem -Prompt "Select a Process" | Stop-Process -ErrorAction SilentlyContinue
#>
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true)]
$InputObject,
[Parameter(Mandatory=$false)]
[string]
$Prompt = "Enter Selection"
)
Begin
{
$menuOptions = @()
}
Process
{
$menuOptions += $InputObject
}
End
{
do
{
[int]$optionNumber = 1
foreach ($option in $menuOptions)
{
Write-Host ("{0,3}: {1}" -f $optionNumber,$option)
$optionNumber++
}
Write-Host ("{0,3}: {1}" -f 0,"To cancel")
[int]$choice = Read-Host $Prompt
$selectedValue = ""
if ($choice -gt 0 -and $choice -le $menuOptions.Count)
{
$selectedValue = $menuOptions[$choice - 1]
}
}
until ($choice -eq 0 -or $choice -le $menuOptions.Count)
return $selectedValue
}
}
“fee fie”, “huff and puff”, “mirror mirror”, “tick tock” | Select-TextItem -Prompt "Select a string"
```
{{Out}}
```txt
1: fee fie
2: huff and puff
3: mirror mirror
4: tick tock
0: To cancel
Select a string: 3
mirror mirror
```
## ProDOS
{{incorrect|ProDOS|The function should return an empty string if called with an empty list. Please also check if this could really used as a [https://en.wikipedia.org/wiki/Subroutine function aka subroutine.]}}