mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-22 14:06:16 +02:00
docs: merge builtin-constants into builtins
This commit is contained in:
parent
fd4b17ab2c
commit
95890b3e1d
16 changed files with 62 additions and 100 deletions
|
@ -1,31 +0,0 @@
|
||||||
let
|
|
||||||
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
|
||||||
inherit (import <nix/utils.nix>) optionalString squash;
|
|
||||||
in
|
|
||||||
|
|
||||||
builtinsInfo:
|
|
||||||
let
|
|
||||||
showBuiltin = name: { doc, type, impure-only }:
|
|
||||||
let
|
|
||||||
type' = optionalString (type != null) " (${type})";
|
|
||||||
|
|
||||||
impureNotice = optionalString impure-only ''
|
|
||||||
> **Note**
|
|
||||||
>
|
|
||||||
> Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
squash ''
|
|
||||||
<dt id="builtins-${name}">
|
|
||||||
<a href="#builtins-${name}"><code>${name}</code></a>${type'}
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
${doc}
|
|
||||||
|
|
||||||
${impureNotice}
|
|
||||||
|
|
||||||
</dd>
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
|
|
@ -5,8 +5,10 @@ in
|
||||||
|
|
||||||
builtinsInfo:
|
builtinsInfo:
|
||||||
let
|
let
|
||||||
showBuiltin = name: { doc, args, arity, experimental-feature }:
|
showBuiltin = name: { doc, type ? null, args ? [ ], experimental-feature ? null, impure-only ? false }:
|
||||||
let
|
let
|
||||||
|
type' = optionalString (type != null) " (${type})";
|
||||||
|
|
||||||
experimentalNotice = optionalString (experimental-feature != null) ''
|
experimentalNotice = optionalString (experimental-feature != null) ''
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
|
@ -18,18 +20,26 @@ let
|
||||||
> extra-experimental-features = ${experimental-feature}
|
> extra-experimental-features = ${experimental-feature}
|
||||||
> ```
|
> ```
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
impureNotice = optionalString impure-only ''
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
squash ''
|
squash ''
|
||||||
<dt id="builtins-${name}">
|
<dt id="builtins-${name}">
|
||||||
<a href="#builtins-${name}"><code>${name} ${listArgs args}</code></a>
|
<a href="#builtins-${name}"><code>${name}${listArgs args}</code></a>${type'}
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
||||||
${experimentalNotice}
|
${experimentalNotice}
|
||||||
|
|
||||||
${doc}
|
${doc}
|
||||||
|
|
||||||
|
${impureNotice}
|
||||||
</dd>
|
</dd>
|
||||||
'';
|
'';
|
||||||
listArgs = args: concatStringsSep " " (map (s: "<var>${s}</var>") args);
|
listArgs = args: concatStringsSep "" (map (s: " <var>${s}</var>") args);
|
||||||
in
|
in
|
||||||
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
concatStringsSep "\n" (attrValues (mapAttrs showBuiltin builtinsInfo))
|
||||||
|
|
|
@ -140,16 +140,10 @@ $(d)/xp-features.json: $(doc_nix)
|
||||||
|
|
||||||
$(d)/src/language/builtins.md: $(d)/language.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(doc_nix)
|
$(d)/src/language/builtins.md: $(d)/language.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(doc_nix)
|
||||||
@cat doc/manual/src/language/builtins-prefix.md > $@.tmp
|
@cat doc/manual/src/language/builtins-prefix.md > $@.tmp
|
||||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<)).builtins' >> $@.tmp;
|
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp;
|
||||||
@cat doc/manual/src/language/builtins-suffix.md >> $@.tmp
|
@cat doc/manual/src/language/builtins-suffix.md >> $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
|
||||||
$(d)/src/language/builtin-constants.md: $(d)/language.json $(d)/generate-builtin-constants.nix $(d)/src/language/builtin-constants-prefix.md $(doc_nix)
|
|
||||||
@cat doc/manual/src/language/builtin-constants-prefix.md > $@.tmp
|
|
||||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtin-constants.nix (builtins.fromJSON (builtins.readFile $<)).constants' >> $@.tmp;
|
|
||||||
@cat doc/manual/src/language/builtin-constants-suffix.md >> $@.tmp
|
|
||||||
@mv $@.tmp $@
|
|
||||||
|
|
||||||
$(d)/language.json: $(doc_nix)
|
$(d)/language.json: $(doc_nix)
|
||||||
$(trace-gen) $(dummy-env) $(doc_nix) __dump-language > $@.tmp
|
$(trace-gen) $(dummy-env) $(doc_nix) __dump-language > $@.tmp
|
||||||
@mv $@.tmp $@
|
@mv $@.tmp $@
|
||||||
|
@ -217,7 +211,7 @@ doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli
|
||||||
# `@docroot@` is to be preserved for documenting the mechanism
|
# `@docroot@` is to be preserved for documenting the mechanism
|
||||||
# FIXME: maybe contributing guides should live right next to the code
|
# FIXME: maybe contributing guides should live right next to the code
|
||||||
# instead of in the manual
|
# instead of in the manual
|
||||||
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/store/types $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(d)/src/language/builtin-constants.md $(d)/src/release-notes/rl-next.md $(d)/src/figures $(d)/src/favicon.png $(d)/src/favicon.svg
|
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/store/types $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(d)/src/release-notes/rl-next.md $(d)/src/figures $(d)/src/favicon.png $(d)/src/favicon.svg
|
||||||
$(trace-gen) \
|
$(trace-gen) \
|
||||||
tmp="$$(mktemp -d)"; \
|
tmp="$$(mktemp -d)"; \
|
||||||
cp -r doc/manual "$$tmp"; \
|
cp -r doc/manual "$$tmp"; \
|
||||||
|
|
|
@ -32,11 +32,10 @@
|
||||||
- [String interpolation](language/string-interpolation.md)
|
- [String interpolation](language/string-interpolation.md)
|
||||||
- [Lookup path](language/constructs/lookup-path.md)
|
- [Lookup path](language/constructs/lookup-path.md)
|
||||||
- [Operators](language/operators.md)
|
- [Operators](language/operators.md)
|
||||||
|
- [Built-ins](language/builtins.md)
|
||||||
- [Derivations](language/derivations.md)
|
- [Derivations](language/derivations.md)
|
||||||
- [Advanced Attributes](language/advanced-attributes.md)
|
- [Advanced Attributes](language/advanced-attributes.md)
|
||||||
- [Import From Derivation](language/import-from-derivation.md)
|
- [Import From Derivation](language/import-from-derivation.md)
|
||||||
- [Built-in Constants](language/builtin-constants.md)
|
|
||||||
- [Built-in Functions](language/builtins.md)
|
|
||||||
- [Package Management](package-management/index.md)
|
- [Package Management](package-management/index.md)
|
||||||
- [Profiles](package-management/profiles.md)
|
- [Profiles](package-management/profiles.md)
|
||||||
- [Garbage Collection](package-management/garbage-collection.md)
|
- [Garbage Collection](package-management/garbage-collection.md)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
/expressions/* /language/:splat 301!
|
/expressions/* /language/:splat 301!
|
||||||
/language/values /language/types 301!
|
/language/values /language/types 301!
|
||||||
/language/constructs /language/syntax 301!
|
/language/constructs /language/syntax 301!
|
||||||
|
/language/builtin-constants /language/builtins 301!
|
||||||
|
|
||||||
/installation/installation /installation 301!
|
/installation/installation /installation 301!
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Built-in Constants
|
|
||||||
|
|
||||||
These constants are built into the Nix language evaluator:
|
|
||||||
|
|
||||||
<dl>
|
|
|
@ -1 +0,0 @@
|
||||||
</dl>
|
|
|
@ -1,9 +1,11 @@
|
||||||
# Built-in Functions
|
# Built-ins
|
||||||
|
|
||||||
This section lists the functions built into the Nix language evaluator.
|
This section lists the values and functions built into the Nix language evaluator.
|
||||||
All built-in functions are available through the global [`builtins`](./builtin-constants.md#builtins-builtins) constant.
|
All built-ins are available through the global [`builtins`](#builtins-builtins) constant.
|
||||||
|
|
||||||
For convenience, some built-ins can be accessed directly:
|
Some built-ins are also exposed directly in the global scope:
|
||||||
|
|
||||||
|
<!-- TODO(@rhendric, #10970): this list is incomplete -->
|
||||||
|
|
||||||
- [`derivation`](#builtins-derivation)
|
- [`derivation`](#builtins-derivation)
|
||||||
- [`import`](#builtins-import)
|
- [`import`](#builtins-import)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
A lookup path is an identifier with an optional path suffix that resolves to a [path value](@docroot@/language/types.md#type-path) if the identifier matches a search path entry.
|
A lookup path is an identifier with an optional path suffix that resolves to a [path value](@docroot@/language/types.md#type-path) if the identifier matches a search path entry.
|
||||||
|
|
||||||
The value of a lookup path is determined by [`builtins.nixPath`](@docroot@/language/builtin-constants.md#builtins-nixPath).
|
The value of a lookup path is determined by [`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath).
|
||||||
|
|
||||||
See [`builtins.findFile`](@docroot@/language/builtins.md#builtins-findFile) for details on lookup path resolution.
|
See [`builtins.findFile`](@docroot@/language/builtins.md#builtins-findFile) for details on lookup path resolution.
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ It outputs an attribute set, and produces a [store derivation] as a side effect
|
||||||
> }
|
> }
|
||||||
> ```
|
> ```
|
||||||
>
|
>
|
||||||
> [`builtins.currentSystem`](@docroot@/language/builtin-constants.md#builtins-currentSystem) has the value of the [`system` configuration option], and defaults to the system type of the current Nix installation.
|
> [`builtins.currentSystem`](@docroot@/language/builtins.md#builtins-currentSystem) has the value of the [`system` configuration option], and defaults to the system type of the current Nix installation.
|
||||||
|
|
||||||
- [`builder`]{#attr-builder} ([Path](@docroot@/language/types.md#type-path) | [String](@docroot@/language/types.md#type-string))
|
- [`builder`]{#attr-builder} ([Path](@docroot@/language/types.md#type-path) | [String](@docroot@/language/types.md#type-string))
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ A _boolean_ in the Nix language is one of _true_ or _false_.
|
||||||
|
|
||||||
<!-- TODO: mention the top-level environment -->
|
<!-- TODO: mention the top-level environment -->
|
||||||
|
|
||||||
These values are available as attributes of [`builtins`](builtin-constants.md#builtins-builtins) as [`builtins.true`](builtin-constants.md#builtins-true) and [`builtins.false`](builtin-constants.md#builtins-false).
|
These values are available as attributes of [`builtins`](builtins.md#builtins-builtins) as [`builtins.true`](builtins.md#builtins-true) and [`builtins.false`](builtins.md#builtins-false).
|
||||||
The function [`builtins.isBool`](builtins.md#builtins-isBool) can be used to determine if a value is a boolean.
|
The function [`builtins.isBool`](builtins.md#builtins-isBool) can be used to determine if a value is a boolean.
|
||||||
|
|
||||||
### String {#type-string}
|
### String {#type-string}
|
||||||
|
@ -60,7 +60,7 @@ There is a single value of type _null_ in the Nix language.
|
||||||
|
|
||||||
<!-- TODO: mention the top-level environment -->
|
<!-- TODO: mention the top-level environment -->
|
||||||
|
|
||||||
This value is available as an attribute on the [`builtins`](builtin-constants.md#builtins-builtins) attribute set as [`builtins.null`](builtin-constants.md#builtins-null).
|
This value is available as an attribute on the [`builtins`](builtins.md#builtins-builtins) attribute set as [`builtins.null`](builtins.md#builtins-null).
|
||||||
|
|
||||||
## Compound values
|
## Compound values
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ struct EvalSettings : Config
|
||||||
R"(
|
R"(
|
||||||
List of search paths to use for [lookup path](@docroot@/language/constructs/lookup-path.md) resolution.
|
List of search paths to use for [lookup path](@docroot@/language/constructs/lookup-path.md) resolution.
|
||||||
This setting determines the value of
|
This setting determines the value of
|
||||||
[`builtins.nixPath`](@docroot@/language/builtin-constants.md#builtins-nixPath) and can be used with [`builtins.findFile`](@docroot@/language/builtin-constants.md#builtins-findFile).
|
[`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath) and can be used with [`builtins.findFile`](@docroot@/language/builtins.md#builtins-findFile).
|
||||||
|
|
||||||
The default value is
|
The default value is
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ struct EvalSettings : Config
|
||||||
this, "", "eval-system",
|
this, "", "eval-system",
|
||||||
R"(
|
R"(
|
||||||
This option defines
|
This option defines
|
||||||
[`builtins.currentSystem`](@docroot@/language/builtin-constants.md#builtins-currentSystem)
|
[`builtins.currentSystem`](@docroot@/language/builtins.md#builtins-currentSystem)
|
||||||
in the Nix language if it is set as a non-empty string.
|
in the Nix language if it is set as a non-empty string.
|
||||||
Otherwise, if it is defined as the empty string (the default), the value of the
|
Otherwise, if it is defined as the empty string (the default), the value of the
|
||||||
[`system` ](#conf-system)
|
[`system` ](#conf-system)
|
||||||
|
@ -116,7 +116,7 @@ struct EvalSettings : Config
|
||||||
R"(
|
R"(
|
||||||
If set to `true`, the Nix evaluator will not allow access to any
|
If set to `true`, the Nix evaluator will not allow access to any
|
||||||
files outside of
|
files outside of
|
||||||
[`builtins.nixPath`](@docroot@/language/builtin-constants.md#builtins-nixPath),
|
[`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath),
|
||||||
or to URIs outside of
|
or to URIs outside of
|
||||||
[`allowed-uris`](@docroot@/command-ref/conf-file.md#conf-allowed-uris).
|
[`allowed-uris`](@docroot@/command-ref/conf-file.md#conf-allowed-uris).
|
||||||
)"};
|
)"};
|
||||||
|
@ -127,10 +127,10 @@ struct EvalSettings : Config
|
||||||
|
|
||||||
- Restrict file system and network access to files specified by cryptographic hash
|
- Restrict file system and network access to files specified by cryptographic hash
|
||||||
- Disable impure constants:
|
- Disable impure constants:
|
||||||
- [`builtins.currentSystem`](@docroot@/language/builtin-constants.md#builtins-currentSystem)
|
- [`builtins.currentSystem`](@docroot@/language/builtins.md#builtins-currentSystem)
|
||||||
- [`builtins.currentTime`](@docroot@/language/builtin-constants.md#builtins-currentTime)
|
- [`builtins.currentTime`](@docroot@/language/builtins.md#builtins-currentTime)
|
||||||
- [`builtins.nixPath`](@docroot@/language/builtin-constants.md#builtins-nixPath)
|
- [`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath)
|
||||||
- [`builtins.storePath`](@docroot@/language/builtin-constants.md#builtins-storePath)
|
- [`builtins.storePath`](@docroot@/language/builtins.md#builtins-storePath)
|
||||||
)"
|
)"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1872,7 +1872,7 @@ static RegisterPrimOp primop_findFile(PrimOp {
|
||||||
- If the suffix is found inside that directory, then the entry is a match.
|
- If the suffix is found inside that directory, then the entry is a match.
|
||||||
The combined absolute path of the directory (now downloaded if need be) and the suffix is returned.
|
The combined absolute path of the directory (now downloaded if need be) and the suffix is returned.
|
||||||
|
|
||||||
[Lookup path](@docroot@/language/constructs/lookup-path.md) expressions are [desugared](https://en.wikipedia.org/wiki/Syntactic_sugar) using this and [`builtins.nixPath`](@docroot@/language/builtin-constants.md#builtins-nixPath):
|
[Lookup path](@docroot@/language/constructs/lookup-path.md) expressions are [desugared](https://en.wikipedia.org/wiki/Syntactic_sugar) using this and [`builtins.nixPath`](#builtins-nixPath):
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
<nixpkgs>
|
<nixpkgs>
|
||||||
|
@ -4519,7 +4519,7 @@ void EvalState::createBaseEnv()
|
||||||
addConstant("builtins", v, {
|
addConstant("builtins", v, {
|
||||||
.type = nAttrs,
|
.type = nAttrs,
|
||||||
.doc = R"(
|
.doc = R"(
|
||||||
Contains all the [built-in functions](@docroot@/language/builtins.md) and values.
|
Contains all the built-in functions and values.
|
||||||
|
|
||||||
Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations:
|
Since built-in functions were added over time, [testing for attributes](./operators.md#has-attribute) in `builtins` can be used for graceful fallback on older Nix installations:
|
||||||
|
|
||||||
|
|
|
@ -228,7 +228,7 @@ public:
|
||||||
While you can force Nix to run a Darwin-specific `builder` executable on a Linux machine, the result would obviously be wrong.
|
While you can force Nix to run a Darwin-specific `builder` executable on a Linux machine, the result would obviously be wrong.
|
||||||
|
|
||||||
This value is available in the Nix language as
|
This value is available in the Nix language as
|
||||||
[`builtins.currentSystem`](@docroot@/language/builtin-constants.md#builtins-currentSystem)
|
[`builtins.currentSystem`](@docroot@/language/builtins.md#builtins-currentSystem)
|
||||||
if the
|
if the
|
||||||
[`eval-system`](#conf-eval-system)
|
[`eval-system`](#conf-eval-system)
|
||||||
configuration option is set as the empty string.
|
configuration option is set as the empty string.
|
||||||
|
|
|
@ -66,7 +66,7 @@ constexpr std::array<ExperimentalFeatureDetails, numXpFeatures> xpFeatureDetails
|
||||||
an impure derivation cannot also be
|
an impure derivation cannot also be
|
||||||
[content-addressed](#xp-feature-ca-derivations).
|
[content-addressed](#xp-feature-ca-derivations).
|
||||||
|
|
||||||
This is a more explicit alternative to using [`builtins.currentTime`](@docroot@/language/builtin-constants.md#builtins-currentTime).
|
This is a more explicit alternative to using [`builtins.currentTime`](@docroot@/language/builtins.md#builtins-currentTime).
|
||||||
)",
|
)",
|
||||||
.trackingUrl = "https://github.com/NixOS/nix/milestone/42",
|
.trackingUrl = "https://github.com/NixOS/nix/milestone/42",
|
||||||
},
|
},
|
||||||
|
|
|
@ -419,35 +419,28 @@ void mainWrapped(int argc, char * * argv)
|
||||||
};
|
};
|
||||||
evalSettings.pureEval = false;
|
evalSettings.pureEval = false;
|
||||||
EvalState state({}, openStore("dummy://"), evalSettings);
|
EvalState state({}, openStore("dummy://"), evalSettings);
|
||||||
auto res = nlohmann::json::object();
|
|
||||||
res["builtins"] = ({
|
|
||||||
auto builtinsJson = nlohmann::json::object();
|
auto builtinsJson = nlohmann::json::object();
|
||||||
for (auto & builtin : *state.baseEnv.values[0]->attrs()) {
|
for (auto & builtin : *state.baseEnv.values[0]->attrs()) {
|
||||||
auto b = nlohmann::json::object();
|
auto b = nlohmann::json::object();
|
||||||
if (!builtin.value->isPrimOp()) continue;
|
if (!builtin.value->isPrimOp()) continue;
|
||||||
auto primOp = builtin.value->primOp();
|
auto primOp = builtin.value->primOp();
|
||||||
if (!primOp->doc) continue;
|
if (!primOp->doc) continue;
|
||||||
b["arity"] = primOp->arity;
|
|
||||||
b["args"] = primOp->args;
|
b["args"] = primOp->args;
|
||||||
b["doc"] = trim(stripIndentation(primOp->doc));
|
b["doc"] = trim(stripIndentation(primOp->doc));
|
||||||
|
if (primOp->experimentalFeature)
|
||||||
b["experimental-feature"] = primOp->experimentalFeature;
|
b["experimental-feature"] = primOp->experimentalFeature;
|
||||||
builtinsJson[state.symbols[builtin.name]] = std::move(b);
|
builtinsJson[state.symbols[builtin.name]] = std::move(b);
|
||||||
}
|
}
|
||||||
std::move(builtinsJson);
|
|
||||||
});
|
|
||||||
res["constants"] = ({
|
|
||||||
auto constantsJson = nlohmann::json::object();
|
|
||||||
for (auto & [name, info] : state.constantInfos) {
|
for (auto & [name, info] : state.constantInfos) {
|
||||||
auto c = nlohmann::json::object();
|
auto b = nlohmann::json::object();
|
||||||
if (!info.doc) continue;
|
if (!info.doc) continue;
|
||||||
c["doc"] = trim(stripIndentation(info.doc));
|
b["doc"] = trim(stripIndentation(info.doc));
|
||||||
c["type"] = showType(info.type, false);
|
b["type"] = showType(info.type, false);
|
||||||
c["impure-only"] = info.impureOnly;
|
if (info.impureOnly)
|
||||||
constantsJson[name] = std::move(c);
|
b["impure-only"] = true;
|
||||||
|
builtinsJson[name] = std::move(b);
|
||||||
}
|
}
|
||||||
std::move(constantsJson);
|
logger->cout("%s", builtinsJson);
|
||||||
});
|
|
||||||
logger->cout("%s", res);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue