challenge 設定ファイルから値を取得

設定ファイルから項目名をキーとして値を取得するコードを書いてください。
設定ファイルのイメージも載せてください。

ここで設定ファイルとは、
 ・項目名と値のペアが書いてあるファイル
 ・フォーマットはその言語で扱いやすいものでよい
 ・コードと分離され、コードに影響を与えずに変更が可能
を条件とします。ファイルが難しければ同等のものでもかまいません(テーブル、環境変数など)。

例)
----
ファイル:ShowPrice.ini
ITEM_NAME=りんご
ITEM_COST=200

> showPrice()
「りんご」は210円(税込み)
----
ITEM_NAME=みかん
ITEM_COST=100

> showPrice()
「みかん」は105円(税込み)

Posted feedbacks - Nested

Flatten Hidden

この頃、自分で書く時はこんな形にしてます。

設定ファイルの内容は

ファイル:ShowPrice.properties

>>

item.name=apple

item.cost=200

<<

ファイル:ShowPrice2.properties

>>

item.name=orange

item.cost=100

<<

ファイル:ShowPrice3.properties

>>

<<

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Properties;


public class Sample186 {
    private static final Properties defaultProperties_ = new Properties();
    static {
        defaultProperties_.setProperty("item.name", "nothing");
        defaultProperties_.setProperty("item.cost", "0");
    }


    private final Properties properties_ = new Properties(defaultProperties_);

    public Sample186(InputStream stream) throws IOException {
        properties_.load(stream);
    }
    public Sample186(Reader reader) throws IOException {
        properties_.load(reader);
    }

    public String get(String key) {
        return properties_.getProperty(key);
    }
    public int getInteger(String key) {
        try {
            return Integer.parseInt(get(key));
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            return 0;
        }
    }
    public long getLong(String key) {
        try {
            return Long.parseLong(get(key));
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            return 0L;
        }
    }
    public double getDouble(String key) {
        try {
            return Double.parseDouble(get(key));
        } catch (NumberFormatException ex) {
            ex.printStackTrace();
            return 0.0;
        }
    }


    public static void main(String[] args) {
        try {
            Sample186 apple = new Sample186(new FileInputStream("ShowPrice.properties"));
            System.out.println(getPrice(apple));
            Sample186 orange = new Sample186(new FileInputStream("ShowPrice2.properties"));
            System.out.println(getPrice(orange));
            Sample186 nothing = new Sample186(new FileInputStream("ShowPrice3.properties"));
            System.out.println(getPrice(nothing));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    private static String getPrice(Sample186 sample186) {
        return String.format("「%s」は%d円(税込み)", sample186.get("item.name"), (int)(sample186.getInteger("item.cost") * 1.05));
    }
}
Squeak Smalltalk で。


ファイル: ShowPrice.ini
ItemName=りんご
ItemCost=200 

出力: 
「りんご」は210円(税込み)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
| file line dict str |
file := FileStream fileNamed: 'ShowPrice.ini'.
file converter: UTF8TextConverter new.
dict := Dictionary new.
[(line := file nextLine) notNil] whileTrue: [
    | stream |
    stream := line readStream.
    dict at: (stream upTo: $=) asSymbol put: stream upToEnd].
file close.
World findATranscript: nil.
str := '「{1}」は{2}円(税込み)'
    format: {dict at: #ItemName. ((dict at: #ItemCost) * 1.05) truncated}.
Transcript cr; show: str
Config::Simple を使うと楽に書けます。

設定ファイル例: ShowPrice.ini
ITEM_NAME=りんご
ITEM_COST=200 

% perl show_price.pl
「りんご」は210円(税込み) 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use strict;
use warnings;
use Config::Simple;

my $cfg = Config::Simple->new('ShowPrice.ini');

sub ShowPrice {
    printf('「%s」は%d円(税込み)',
           $cfg->param('ITEM_NAME'),
           $cfg->param('ITEM_COST') * 1.05);
}

ShowPrice();
Boost.Spirit を使って。
Javaのpropertiesファイルみたいな
KEY = VALUE
KEY2 = VALUE2
:
形式のファイルを読み込みます。

#で始まる行はコメントとして読み飛ばします。
また、KEYに使えるのがアルファベット、数字、
アンダーバー、ハイフンのみという制約が
あります。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <map>
#include <string>
#include <stdexcept>
#include <fstream>

#include <boost/spirit.hpp>
#include <boost/spirit/actor/assign_actor.hpp>
#include <boost/spirit/actor/insert_at_actor.hpp>
#include <boost/algorithm/string/trim.hpp>

class PropertyFileReader
{
    public:
        //! key-value paired map type
        typedef std::map<std::string, std::string> property_map_type;

    public:
        static property_map_type
            read(
                    std::istream& is
                );

};


PropertyFileReader::property_map_type
PropertyFileReader::read(
        std::istream& is
        )
{
    using namespace boost::spirit;

    property_map_type prop;
    property_map_type::key_type prop_key;

    rule<> comment_r = comment_p("#");
    rule<> name_r = (alpha_p | ch_p('_')) >> *( alnum_p | ch_p('_') | ch_p('-'));
    rule<> key_r = name_r[assign_a(prop_key)];
    rule<> value_r = (*(anychar_p - eol_p))[insert_at_a(prop, prop_key)];

    rule<> kvpair_r = (key_r >> *blank_p >> ch_p('=') >> *blank_p >> value_r);

    rule<> commentline_r = *blank_p >> comment_r;
    rule<> emptyline_r = *blank_p >> eol_p;
    rule<> kvpairline_r = *blank_p >> kvpair_r >> eol_p;

    rule<> prop_r = *( commentline_r || emptyline_r || kvpairline_r ) >> end_p;

    // slurp stream
    std::string content;
    while ( !is.eof() ) {
        std::string line;
        std::getline(is,line);
        content += line + "\n";
    }

    parse_info<> result = parse(content.c_str(), prop_r);

    if ( !result.full ) {
        throw std::runtime_error("couldn't parse properties");
    }

    // trim following white spaces in value
    for ( property_map_type::iterator it = prop.begin(); it != prop.end(); ++it )
        boost::algorithm::trim(it->second);

    return prop;
}

int main(int c, char** v)
{
  if ( c != 3 ) {
    std::cout << "usage " << v[0] << " <property file> <key name>\n";
    return 0;
  }

  try {
    PropertyFileReader::property_map_type map(
        PropertyFileReader().read(std::ifstream(v[1])) );

    std::cout << v[2] << " = " << map[std::string(v[2])] << "\n";
  }
  catch ( const std::exception& e ) {
    std::cerr << "ERROR: " << e.what() << "\n";
    return 1;
  }
  return 0;
}
Xmlシリアライズが便利です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.IO;
using System.Xml.Serialization;

class Program {
    static void Main(string[] args) {
        string Path = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + "\\ShowPrice.xml";
        XmlSerializer serializer = new XmlSerializer(typeof(Item));

        //値セット
        Item item = new Item { Name = "りんご", Cost = 200 };

        //書き込み
        using(StreamWriter sw = new StreamWriter(Path)) {
            serializer.Serialize(sw, item);
        }

        //ファイル内容表示
        using(StreamReader sr = new StreamReader(Path)) {
            Console.WriteLine(sr.ReadToEnd());
        }
        Console.ReadLine();

        //読み込み,表示
        using(StreamReader sr = new StreamReader(Path)) {
            item = (Item)(serializer.Deserialize(sr));
        }
        Console.WriteLine("「{0}」は{1}円(税込み)", item.Name, item.Cost * 1.05);
        Console.ReadLine();
    }
}

public class Item {
    public string Name { set; get; }
    public int Cost { set; get; }
}
WinAPIを叩いてINIファイルを読み書きするコードも挙げようと思ったのですが、
誰かがC辺りで書いてくれるのを期待します。
.NETでWinAPI使うとコードが読みにくくなるんですよね。
今更ながらの、ini file 形式で、
キーと値は、ファイルに一つだけなのか、そうでないのかよくわかりませんでしたので、特に全部読み出すような処理はしていません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;

class IniFileHandler {
  [DllImport("KERNEL32.DLL")]
  public static extern uint
    GetPrivateProfileString(string lpAppName,
    string lpKeyName, string lpDefault,
    StringBuilder lpReturnedString, uint nSize,
    string lpFileName);

  [DllImport("KERNEL32.DLL",
      EntryPoint="GetPrivateProfileStringA")]
  public static extern uint
    GetPrivateProfileStringByByteArray(string lpAppName,
    string lpKeyName, string lpDefault,
    byte [] lpReturnedString, uint nSize,
    string lpFileName);

  [DllImport("KERNEL32.DLL")]
  public static extern uint
    GetPrivateProfileInt( string lpAppName,
    string lpKeyName, int nDefault, string lpFileName );

  [DllImport("KERNEL32.DLL")]
  public static extern uint WritePrivateProfileString(
    string lpAppName,
    string lpKeyName,
    string lpString,
    string lpFileName);
}

public class Sample {
  static void Main() {

    // キーと値を書き加える
    IniFileHandler.WritePrivateProfileString("Sample1", "ITEM_NAME", "りんご", @".\ShowPrice.ini");
    IniFileHandler.WritePrivateProfileString("Sample1", "ITEM_COST", "200",    @".\ShowPrice.ini");
    IniFileHandler.WritePrivateProfileString("Sample2", "ITEM_NAME", "みかん", @".\ShowPrice.ini");
    IniFileHandler.WritePrivateProfileString("Sample2", "ITEM_COST", "100",    @".\ShowPrice.ini");

    StringBuilder name = new StringBuilder(1024);
    uint cost = 0;
   
    IniFileHandler.GetPrivateProfileString("Sample1", "ITEM_NAME", "", name, (uint)name.Capacity, @".\ShowPrice.ini");
    cost = IniFileHandler.GetPrivateProfileInt("Sample1", "ITEM_COST", 0, @".\ShowPrice.ini");
    Console.WriteLine("「{0}」は{1}円(税込み)", name, cost*1.05);

    IniFileHandler.GetPrivateProfileString("Sample2", "ITEM_NAME", "", name, (uint)name.Capacity, @".\ShowPrice.ini");
    cost = IniFileHandler.GetPrivateProfileInt("Sample2", "ITEM_COST", 0, @".\ShowPrice.ini");
    Console.WriteLine("「{0}」は{1}円(税込み)", name, cost*1.05);

  }
}
設定ファイルをS式で書けば、READで読み込めるので便利です。

ファイル: ShowPrice.ini
((item-name . りんご)
 (item-cost . 200))

出力: 
(show-price)
=> 「りんご」は210円(税込み)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(defvar *show-price-initfile* "ShowPrice.ini")

(defun show-price (&optional (file *show-price-initfile*) (out *standard-output*))
  (with-open-file (str file :direction :input :external-format :utf-8)
    (let ((in (read str)))
      (let ((name (cdr (assoc 'item-name in)))
            (cost (cdr (assoc 'item-cost in))))
        (with-tax 105 (cost)
          (format out "「~A」は~D円(税込み)~%" name cost))))))

(defmacro with-tax (rate (&rest vars) &body body)
  `(let ,(mapcar (lambda (v) `(,v (truncate (* ,rate ,v) 100))) vars)
     ,@body))

読み込みは手を抜いてしまいました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

struct Price
{
    std::string name;
    int         cost;
};

Price loadPrice(std::istream& in)
{
    Price result = { "", 0 };

    std::string line;
    while(std::getline(in, line))
    {
        std::string::size_type p = line.find("=");
        std::string key          = line.substr(0, p);
        std::string value        = line.substr(p + 1);
        if(key == "ITEM_NAME")
        {
            result.name = value;
        }
        else if(key == "ITEM_COST")
        {
            std::stringstream ss;
            ss << value;
            ss >> result.cost;
        }
    };

    return result;
}

void showPrice(const Price& price)
{
    std::cout << "「" << price.name << "」は" << static_cast<int>(price.cost * 1.05) << "円(税込み)" << std::endl;
}

int main(int, char* [])
{
    std::ifstream source("ShowPrice.ini");
    if(source.good())
    {
        Price price = loadPrice(source);
        showPrice(price);
    }
    return 0;
}
config.groovyという設定ファイルが用意されている場合です。

------------------------------
ITEM_NAME="りんご"
ITEM_COST=200
------------------------------
1
2
3
4
5
6
def showPrice(){
    def config = new ConfigSlurper().parse(new File('config.groovy').toURL()) 
    println "「${config.ITEM_NAME}」は${(int)(config.ITEM_COST*1.05)}円(税込み) "
}

showPrice()

Item型を定義して、これをReadクラスおよびShowクラスのインスタンスとする

-- ShowPrice.ini
Item { name = りんご, cost = 200 }

日本語を扱うには System.IO.UTF8 モジュールを使うので ShowPrice.iniはUTF8で記述する

1
2
3
4
5
6
7
8
9
import qualified System.IO.UTF8 as U
import Text.Printf

data Item = Item { name :: String, cost :: Int } deriving (Read)

instance Show Item where
  show i = printf "「%s」は%d円(税込)" (name i) (cost i * 105 `div` 100)

main = U.print . (read :: String -> Item) =<< U.readFile "ShowPrice.ini"
ConfigParserを使います。ShowPrice.ini は下のような形式で。

[item]
name=りんご
cost=200
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# coding: shift_jis

from ConfigParser import ConfigParser

def main():
    parser = ConfigParser()
    parser.read("ShowPrice.ini")
    name = parser.get("item", "name")
    cost = int(parser.get("item", "cost"))
    print "「%s」は%d円(税込み)" % (name, cost * 1.05)

if __name__ == '__main__':
    main()

ctypes+Win32APIで。初期化ファイルは前と同じ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# coding: shift_jis

import ctypes
import os

def main():
    path = os.path.abspath("ShowPrice.ini")
    dll = ctypes.windll.kernel32
    buf = ctypes.create_string_buffer(1000)
    dll.GetPrivateProfileStringA("item", "name", "", buf, len(buf), path)
    name = buf.value
    cost = dll.GetPrivateProfileIntA("item", "cost", 0, path)
    print "「%s」は%d円(税込み)" % (name, cost * 1.05)

if __name__ == '__main__':
    main()

PerlのConfig::Simple かっこいいっす

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
-------------------------------------------

ITEM_NAME=りんご
ITEM_COST=200

-------------------------------------------

#include <stdio.h>
#include <string.h>

#define SIZE 256
#define ITEM_NAME "ITEM_NAME"
#define ITEM_COST "ITEM_COST"

char* get_value(const char *path, const char *key, char *value) {
    char buf[SIZE];
    FILE *f;
    char *key_ptr, *val_ptr;

    f = fopen(path, "r");
    while(fgets(buf, sizeof buf, f) != NULL) {
        if((key_ptr = strstr(buf, key)) != NULL) {
            if((val_ptr = strchr(key_ptr, '=')) != NULL) {
                strcpy(value, ++val_ptr);
            }
        }
    }
    *(value + strlen(value) -1) = '\0';
    return value;
}

int main(int argc, char *argv[])
{
    char value1[SIZE], value2[SIZE];
    char path[] = "ShowPrice.ini";

    get_value(path, ITEM_NAME, value1);
    get_value(path, ITEM_COST, value2);
    printf("「%s」は%.f円(税込み)", value1, (atoi(value2)*1.05));

    return 0;
}
久々に使ったので、いろいろ忘れてます。
-- ShowPrice.ini
[doukaku186]
ITEM_NAME=りんご
ITEM_COST=200
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
program doukaku186;

{$APPTYPE CONSOLE}

uses
  IniFiles, SysUtils;

var
  Name: String;
  Cost: Integer;
begin
  with TIniFile.Create(ExtractFilePath(ParamStr((0)))+'\ShowPrice.ini') do
  begin
    try
      Name := ReadString('doukaku186', 'ITEM_NAME', '');
      Cost := ReadInteger('doukaku186', 'ITEM_COST', 0);
      WriteLn('「', Name, '」は', Cost * 105 div 100, '円(税込み)');
    finally
      Free;
    end;
  end
end.
なでしこでは標準でINIファイル関連の関数があるので、それを使います。
Windows標準形式で以下のようにします。

ShowPrice.ini
[item]
name=りんご
cost=200
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
●ShowPrice
    Hとは整数 #ハンドル
    nameとは文字列
    costとは文字列
    H="{母艦パス}ShowPrice.ini"のINI開く
    name=Hで"item"の"name"をINI読む
    cost=Hで"item"の"cost"をINI読む
    HのINI閉じる
    "「{name}」は{cost * 1.05}円(税込み)"を表示 

ShowPrice

上、言語を選び損ねましたorz

標準のINI関数ではセクションがないと値を取得できないので、セクションがないファイルの場合は「ハッシュ変換」を使うと便利です。

ShowPrice.ini name=りんご cost=200

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
●ShowPrice
    tmpとは文字列
    nameとは文字列
    costとは文字列
    tmp="{母艦パス}ShowPrice.ini"を開いてハッシュ変換
    name=tmp@"name"
    cost=tmp@"cost"
    "「{name}」は{cost * 1.05}円(税込み)"を表示 

ShowPrice
普通 PostScript ではプリンタ依存性が大きくなるので外部ファイルの読み込みをユーザープログラムでやることはないと思います。
ここでは GhostScript で試しています。

ShowPrice.ini
--- Cut Here ---
/ITEM_NAME (リンゴ)
/ITEM_COST 200
--- Cut Here ---
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
%!PS

/ReadPrice { % (filename.ini)  ReadPrice  -dict-
    << exch runlibfile >>
} bind def

% --- Test Code ---

(ShowPrice.ini) ReadPrice

dup (ITEM_NAME) get
(「) print print (」は) print

dup (ITEM_COST) get
1.05 mul 0.5 add cvi 10 string cvs print (円(税込み)) =

pop
S式 で書いて read で読みます。

$ cat ShowPrice.ini
((item-name . "りんご") (item-cost . 200))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
(define add-tax (lambda (cost)
  (inexact->exact (floor (+ cost (/ (* cost 5) 100))))))

(define show-price (lambda (file)
  (let ((data (call-with-input-file file (lambda (in) (read in)))))
    (let ((item-name (assq 'item-name data)) (item-cost (assq 'item-cost data)))
      (if (and (pair? item-name) (pair? item-cost))
        (let ((name (cdr item-name)) (cost (cdr item-cost)))
          (if (and (string? name) (number? cost))
            (begin
              (display (string-append "「" name "」は"
                (number->string (add-tax cost)) "円(税込み)"))
              (newline)))))))))

(define main (lambda (args)
  (show-price "ShowPrice.ini")
  0))

データフレームとして読み込んでから名前つきベクトルに変換することで連想配列と同様の機能が使えますが、

要素数が2つ程度であればデータフレームのまま使っちゃった方が早いと思います。

1
2
3
4
showPrice <- function(){
    d <- read.table("ShowPrice.ini", sep="=", stringsAsFactors=FALSE)
    sprintf("「%s」は%d円(税込み)", d$V2[d$V1=="ITEM_NAME"], as.numeric(d$V2[d$V1=="ITEM_COST"])*1.05)
}
XMLのフィードの場合
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
--------------------
<?xml version="1.0" encoding="Shift_JIS" ?> 
<ShowPrice>
   <goods ITEM_NAME="りんご" ITEM_COST="200" />
   <goods ITEM_NAME="みかん" ITEM_COST="100" />
</ShowPrice>
--------------------


showPrice()

def showPrice() {
    def ShowPriceData = new XmlParser().parse(new File(args[0]))
        print  "「"+ShowPriceData.goods[0].'@ITEM_NAME'+"」は"
        println  "("+((ShowPriceData.goods[0].'@ITEM_COST').toInteger()*1.05).toInteger()+")円"
}
YAML形式が楽ですね。 設定ファイル(show_price.yaml)はこんな感じ。 item_name: りんご item_cost: 200
1
2
3
4
5
6
7
$KCODE = 'sjis'

require 'yaml'

config = YAML.load_file("show_price.yaml")

puts "「#{config['item_name']}」は#{config['item_cost']}円(税込み)"
いかん。コメントの形式を間違えて設定ファイルのフォーマットが
崩れてしまった。正しくはこう(↓)です。

item_name: りんご
item_cost: 200
こーゆーのが、XSLTの本来の使い方かと。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  >

  <!-- 以下のようなxml文書を渡します
  <item name="りんご" cost="200" />
  -->

  <xsl:output method="text" encoding="sjis" />

  <xsl:template match="/item" >
    <xsl:call-template name="showPrice" />
  </xsl:template>

  <xsl:template name="showPrice">
    <xsl:text>「</xsl:text>
    <xsl:value-of select="@name" />
    <xsl:text>」は</xsl:text>
    <xsl:value-of select="floor(@cost * 1.05)" />
    <xsl:text>円(税込み)です。&#xA;</xsl:text>
  </xsl:template>

</xsl:stylesheet>
やはりshellかと。
b-shellですが、kshやbashやzshなどでもよいかと。
[ShowProc.ini]
ITEM_NAME=りんご
ITEM_COST=200
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/sh
. ./ShowPrice.ini

showPrice()
{
        cat <<- EOF
        「${ITEM_NAME}」は${ITEM_COST}円(税込み)
EOF
}

showPrice

exit 0
設定ファイルのフォーマットは S式の連想リストです。
ファイルの内容を一時バッファに格納し、そのバッファを
read で読み込んでいます。

ファイル:ShowPrice.ini
((item-name . りんご)
 (item-cost . 200))

> (show-price)
=> "「りんご」は210円(税込み)"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
(defun show-price ()
  (let ((call-with-input-file #'(lambda (filename proc)
                                  (with-temp-buffer
                                    (progn (insert-file-contents filename)
                                           (funcall proc (current-buffer))))))
        (call-with-name&cost #'(lambda (alist proc)
                                 (funcall proc
                                          (cdr (assq 'item-name alist))
                                          (cdr (assq 'item-cost alist)))))
        (call-with-add-tax #'(lambda (rate base proc)
                               (funcall proc (/ (* base (+ rate 100)) 100)))))
    (funcall call-with-input-file (expand-file-name "ShowPrice.ini")
             #'(lambda (in)
                 (funcall call-with-name&cost (read in)
                          #'(lambda (name cost)
                              (funcall call-with-add-tax 5 cost
                                       #'(lambda (cost)
                                           (format "「%s」は%d円(税込み)" name cost)))))))))

Infernoシェルです。 runはUNIXシェルの.と同じで、()は配列表記のため''を使ってエスケープ。 expr式では、めんどくさいことをしてますね。

showprice.ini:

ITEM_NAME=りんご
ITEM_COST=200
1
2
3
4
5
6
7
#!/dis/sh
load std
load expr

run showprice.ini

echo 「$ITEM_NAME」は${expr $ITEM_COST $ITEM_COST 5 x 100 / +}'円(税込み)'