在我的Informix 4GL程序中,我有一个输入字段,用户可以在其中插入URL,然后通过脚本将提要发送到Web。 如何在输入时验证URL,以确保它是实时链接?我可以拨打电话,看看我是否收到任何错误?
答案 0 :(得分:2)
没有内置功能(当I4GL被发明时,URL并不存在)。
如果你可以设计一个C方法,你可以安排通过C接口调用该方法。您将在本机C中编写该方法,然后使用常规规则编写I4GL可调用C接口函数。使用I4GL c代码构建程序时,您也可以链接额外的C函数。如果使用I4GL-RDS(p代码)构建程序,则需要构建一个带有额外功能的自定义运行程序。所有这些都是I4GL的标准技术。
一般而言,您需要的C接口代码看起来很模糊:
#include <fglsys.h>
// Standard interface for I4GL-callable C functions
extern int i4gl_validate_url(int nargs);
// Using obsolescent interface functions
int i4gl_validate_url(int nargs)
{
if (nargs != 1)
fgl_fatal(__FILE__, __LINE__, -1318);
char url[4096];
popstring(url, sizeof(url));
int r = validate_url(url); // Your C function
retint(r);
return 1;
}
您可以而且应该检查manuals但该代码,使用旧样式&#39;函数名称,应该正确编译。代码可以在I4GL中调用,如下所示:
DEFINE url CHAR(256)
DEFINE rc INTEGER
LET url = "http://www.google.com/"
LET rc = i4gl_validate_url(url)
IF rc != 0 THEN
ERROR "Invalid URL"
ELSE
MESSAGE "URL is OK"
END IF
或沿着这些一般路线。您返回的确切值取决于您关于如何从validate_url()
返回状态的决定。如果需要,可以从接口函数返回多个值(例如错误号和错误消息的文本)。等等。这是关于调用一些C代码来验证I4GL程序中的URL的最简单的设计。
接口库中的函数名称在00年代中期都已更改,但旧名称仍然以宏的形式存在。旧名称是:
popstring(char *buffer, int buflen)
retint(int retval)
fgl_fatal(const char *file, int line, int errnum)
您可以在IBM Informix 4GL v7.50.xC3: Publication library in PDF的4GL Reference Manual找到修订后的文档,您需要附录C&#34;将C与IBM Informix 4GL一起使用&#34;。
新名称开始ibm_lib4gl_
:
ibm_libi4gl_popMInt()
ibm_libi4gl_popString()
关于错误报告功能,有一个 - 它存在 - 但我不能再访问文档了。它将位于fglsys.h
标题中。它将错误号作为一个参数;这里有文件名和行号作为其他参数。它可能会ibm_lib4gl_…
,并且可能会Fatal
或者fatal
(或者Err
或err
)其余的名字。
编写shell脚本以获取状态代码会不会更容易?如果我可以将状态代码或任何现有结果返回给程序变量,那可能会有用吗?我能这样做吗?
很可能。但是,如果您希望将URL的内容作为字符串,那么您可能最终想要调用C.当然,值得考虑的是从I4GL中调用shell脚本是否可行。如果是这样,它将更简单(RUN "script"
,IIRC,其中文字字符串可能会被包含命令和URL的组合字符串替换)。我相信现在I4GL中也有文件I / O功能,所以如果你可以让脚本写一个文件(平凡),你可以从文件中读取数据而无需自定义C.很长一段时间,你需要自定义C来做到这一点。
我只需要在将URL存储到数据库之前验证URL。我在考虑:
#!/bin/bash read -p "URL to check: " url if curl --output /dev/null --silent --head --fail "$url"; then printf '%s\n' "$url exist" else printf '%s\n' "$url does not exist" fi
但我只需要将输出而不是
/dev/null
放入变量中。我相信唯一的选择是将输出转储到临时文件中并从那里读取。
让I4GL运行脚本来验证URL,而不是让I4GL运行代码来验证URL。使用脚本的退出状态并将curl
的输出转储到/dev/null
。
FUNCTION check_url(url)
DEFINE url VARCHAR(255)
DEFINE command_line VARCHAR(255)
DEFINE exit_status INTEGER
LET command_line = "check_url ", url
RUN command_line RETURNING exit_status
RETURN exit_status
END FUNCTION {check_url}
您的调用代码可以分析exit_status
以查看它是否有效。值为0表示成功;非零表示某种类型的问题,可以认为该网址不起作用。
确保check_url
脚本(a)在成功时退出状态为零,在任何类型的失败时退出非零,并且(b)不向标准输出写入任何内容(或标准错误)默认情况下。写入标准错误或输出将搞砸屏幕布局等,你不希望这样。 (您显然可以选择启用标准输出的脚本,或者您可以使用选项调用脚本来抑制标准输出和标准错误,或者将输出重定向到/dev/null
;但是,当I4GL程序使用时,应该保持沉默。)
您的脚本&#39; (check_url
)可以简单如下:
#!/bin/bash exec curl --output /dev/null --silent --head --fail "${1:-http://www.example.com/"
这会将第一个参数传递给curl
,或者如果没有给出参数则传递不存在的example.com
URL,并将其自身替换为curl
,这将生成零/非零根据需要退出状态。您可以将2>/dev/null
添加到命令行的末尾,以确保看不到错误消息。 (请注意,如果出现任何问题,将会调试此问题;请确保您已准备好进行调试。)
exec
是次要优化;你可以省略它,结果几乎没有差别。 (我可以设计一个可能发现差异的方案;它涉及发信号通知curl
进程 - kill -9 9999
或类似,其中9999
是curl
的PID过程 - 并没有实际意义。)
鉴于脚本只是调用另一个程序的一行代码,因此可以在I4GL程序中嵌入所有这些代码。但是,拥有外部shell脚本(或Perl脚本,或......)具有灵活性的优点;您可以编辑它以记录尝试,例如,根本不更改I4GL代码。还有一个要分发的文件,但更好的灵活性 - 保留一个单独的脚本,即使它可以全部嵌入到I4GL中。
答案 1 :(得分:0)
正如Jonathan所说,“当I4GL被发明时,URL并不存在”。你会发现已经成长为超级Informix-4gl的产品,如FourJs Genero,将迎合I4GL之后发明的新技术和其他东西。
使用FourJs Genero,使用您熟悉的Informix 4gl语法后,下面的代码将完成您的工作
IMPORT com
MAIN
-- Should succeed and display 1
DISPLAY validate_url("http://www.google.com")
DISPLAY validate_url("http://www.4js.com/online_documentation/fjs-fgl-manual-html/index.html#c_fgl_nf.html") -- link to some of the features added to I4GL by Genero
-- Should fail and display 0
DISPLAY validate_url("http://www.google.com/testing")
DISPLAY validate_url("http://www.google2.com")
END MAIN
FUNCTION validate_url(url)
DEFINE url STRING
DEFINE req com.HttpRequest
DEFINE resp com.HttpResponse
-- Returns TRUE if http request to a URL returns 200
TRY
LET req = com.HttpRequest.create(url)
CALL req.doRequest()
LET resp = req.getResponse()
IF resp.getStatusCode() = 200 THEN
RETURN TRUE
END IF
-- May want to handle other HTTP status codes
CATCH
-- May want to capture case if not connected to internet etc
END TRY
RETURN FALSE
END FUNCTION