Next Previous Contents

4. Samples

4.1 A simple case

#Specbeg: guru samples / simple ([samples.tlcc,123])

        /*
            This simple gurus is used to send an email.
            In this case, we have two questions asked one after the other.
        
            We are using the gurusteps component. For each step in this
            gurus (2 steps, one for the address and one for the subject)
            we have an eval and a dialog node. The gurusteps allows
            up to 6 steps (so we have eval1, eval2, eval3 ... and dialog1,
            dialog2, dialog3 ....)
        */
        <mod>
        static void samples_simple()
        {
            <glocal>
                SSTRING addr;
                SSTRING subject;
            </glocal>
            int ret = <call gurumanage>("simple"
                ,"This is a samples_simple()\n"
                 "It is a 2 steps guru",help_nil);
                <f exec>
                    <call gurusteps>(mode,status);
                        <f eval1>
                            settitle ("Email address");
                            status.is_filled = !glocal.addr.is_empty();
                            status.some_errors = status.is_filled
                                && glocal.addr.strchr('@')==NULL;
                        </f>
                        <f dialog1>
                            setintro ("Enter the email address of the recipient\n"
                                    "An address generally goes like:\n"
                                    "user@some_domain.com");
                            dia.newf_str ("Address",glocal.addr);
                            edit ();
                        </f>
                        <f eval2>
                            settitle ("Subject");
                            status.is_filled = glocal.subject.is_empty();
                            // Subject not validated
                        </f>
                        <f dialog2>
                            dia.newf_str ("",glocal.subject,60);
                            edit();
                        </f>
                    </call>
                </f>
            </call>
            if (ret != -1){
                xconf_notice ("Mail %s\nwill be sent to %s",glocal.subject.get()
                    ,glocal.addr.get());
            }
        }
        </mod>

4.2 A simple case, 2 branches

#Specbeg: guru samples / one choice ([samples.tlcc,179])

        /*
            This gurus is used to send an email. Like the simple one.
            Once the address and subject are filled, we must decide how to send
            it. So there is a decision node allowing us to branch.
            We go either the SMTP way or using another protocol.
            Each branch asks a single question.
        */
        <mod>
        static void samples_simple_smtp()
        {
            <glocal>
                SSTRING addr;
                SSTRING subject;
                SSTRING smtpserv;
                SSTRING planet;
                char smtp;
                bool smtp_filled;
            </glocal>
            glocal.smtp = 1;
            glocal.smtp_filled = false;
            int ret = <call gurumanage>("simple-smtp"
                ,"This is samples_simple_smtp()\n"
                 "This gurus provide 2 steps to define a mail message\n"
                 "and let you choose 2 ways of sending it",help_nil);
                <f exec>
                    <call gurusteps>(mode,status);
                        <f eval1>
                            settitle ("Email address");
                            status.is_filled = !glocal.addr.is_empty();
                            status.some_errors = status.is_filled
                                && glocal.addr.strchr('@')==NULL;
                        </f>
                        <f dialog1>
                            setintro ("Enter the email address of the recipient\n"
                                    "An address generally goes like:\n"
                                    "user@some_domain.com");
                            dia.newf_str ("Address",glocal.addr);
                            edit ();
                        </f>
                        <f eval2>
                            settitle ("Subject");
                            status.is_filled = !glocal.subject.is_empty();
                            // Subject not validated
                        </f>
                        <f dialog2>
                            dia.newf_str ("",glocal.subject,60);
                            edit();
                        </f>
                        <f eval3>
                            settitle ("How to send email");
                            status.is_filled = glocal.smtp_filled;
                        </f>
                        <f dialog3>
                            setintro ("You can send email using two protocols");
                            dia.newf_radio ("",glocal.smtp,1,"Using smtp");
                            dia.newline();
                            dia.newf_radio ("",glocal.smtp,0,"Another protocol");
                            if (edit()) glocal.smtp_filled = true;
                        </f>
                        <f path1>
                            <call gurusteps>(mode,status);
                                <f eval1>
                                    settitle ("SMTP server");
                                    // We can't tell if this node is possible
                                    // until the protocol selection has been
                                    // visited. Since glocal.smtp is either 1 or
                                    // 0, we are using a separate variable
                                    // to tell if the node was visited.
                                    status.is_possible = glocal.smtp == 1
                                        && glocal.smtp_filled;
                                    status.is_filled = !glocal.smtpserv.is_empty();
                                    setterminal ("SMTP mailer","Sending using SMTP protocol");
                                </f>
                                <f dialog1>
                                    dia.newf_str ("Server (IP or Name)",glocal.smtpserv);
                                    edit();
                                </f>
                            </call>
                        </f>
                        <f path2>
                            <call gurusteps>(mode,status);
                                <f eval1>
                                    settitle ("On which planet");
                                    status.is_possible = glocal.smtp == 0
                                        && glocal.smtp_filled;
                                    status.is_filled = !glocal.planet.is_empty();
                                    setterminal ("ET mailer","Sending using out of space protocol");
                                </f>
                                <f dialog1>
                                    dia.newf_str ("Planet",glocal.planet);
                                    edit();
                                </f>
                            </call>
                        </f>
                    </call>
                </f>
            </call>
            if (ret != -1){
                if (glocal.smtp){
                    xconf_notice ("Mail %s\nwill be sent to %s\nusing the SMTP server %s",glocal.subject.get()
                        ,glocal.addr.get(),glocal.smtpserv.get());
                }else{
                    xconf_notice ("Mail %s\nwill be sent to %s\non planet %s",glocal.subject.get()
                        ,glocal.addr.get(),glocal.planet.get());
                }
            }
        }
        </mod>

4.3 Iteration

#Specbeg: guru samples / repeating a step a few times ([samples.tlcc,380])

        /*
            A gurus may have to ask a question several time, for example
            to configure all available network interface. Instead of using
            a gurusteps component and repeat the same code again and again, we
            use the guruiter component. Like the gurupath component, it has
            an eval and dialog function as well as the path1 to path6 function.
        
            But the eval and dialog are providing an extra parameter "step"
            telling us where we are in the iteration.
        
            The following example configure 3 network devices
        */
        <mod>
        static void samples_inter3()
        {
            <glocal>
                SSTRING network[3];
                SSTRING netmask[3];
            </glocal>
            int ret = <call gurumanage>("inter3"
                ,"This is samples_inter3()\n"
                 "It grabs the configuration of 3 network interfaces\n"
                 "repeating the same guru node 3 times",help_nil);
                <f exec>
                    <call guruiter>(3,mode,status);
                        <f eval>
                            SSTRING tmp;
                            tmp.setfromf ("Interface number %d",step+1);
                            settitle (tmp.get());
                            const char *net = glocal.network[step].get();
                            status.is_filled = net[0] != '\0';
                            status.some_errors = status.is_filled
                                && !ipnum_validip (net,false);
                        </f>
                        <f dialog>
                            setintro ("Enter the network definition");
                            dia.newf_str ("network number",glocal.network[step]);
                            dia.newline();
                            dia.newf_str ("netmask",glocal.netmask[step]);
                            edit ();
                        </f>
                    </call>
                </f>
            </call>
            if (ret != -1){
                xconf_notice ("Interfaces configured");
            }
        }
        </mod>
        
        
        
        
        <mod>
        int main (int argc, char *argv[])
        {
            <glocal>
            </glocal>
            return <call tlmpprogram>(argc,argv,"guruengine");
                <f usage>
                    fprintf (stderr,"/tmp/x gurupath\n");
                    fprintf (stderr,"/tmp/x simple\n");
                    fprintf (stderr,"/tmp/x simple-smtp\n");
                    fprintf (stderr,"/tmp/x inter3\n");
                    fprintf (stderr,"/tmp/x combine\n");
                </f>
                <f main>
                    int ret = 0;
                    dialog_clear();
                    if (argc != 1){
                        usage();
                        ret = -1;
                    }else if (strcmp(argv[0],"gurupath")==0){
                        samples_gurupath();
                    }else if (strcmp(argv[0],"simple")==0){
                        samples_simple();
                    }else if (strcmp(argv[0],"simple-smtp")==0){
                        samples_simple_smtp();
                    }else if (strcmp(argv[0],"inter3")==0){
                        samples_inter3();
                    }else if (strcmp(argv[0],"combine")==0){
                        samples_combine();
                    }else{
                        ret = -1;
                    }
                    return ret;
                </f>
            </call>
        }
        </mod>

4.4 Combining gurus

#Specbeg: guru samples / combining chunk of code ([samples.tlcc,291])

        /*
            A guru may by built by reusing smaller ones. Here is an example
            where two independant tasks are merged as a larger one.
        
            The main goal of a guru is at first, to help someone configure
            something from scratch. Because of its graphical map, it is also
            a great way to review a large configuration. If some time is
            invested in more validation, especially global validation and the
            status.some_errors is maintained, the map become a powerful way
            to review a configuration.
        */
        <mod>
        static void samples_config_smtp(GURUPATH_MODE mode, GURUPATH_STATUS &status)
        {
            <glocal>
                SSTRING gateway;
                int interval;
            </glocal>
            glocal.interval = -1;
            // We must read the configuration here
            <call gurusteps>(mode,status);
                <f eval1>
                    settitle ("Email gateway");
                    status.is_filled = !glocal.gateway.is_empty();
                </f>
                <f dialog1>
                    setintro ("Enter the IP address of the SMTP gateway");
                    dia.newf_str ("IP number",glocal.gateway);
                    edit ();
                </f>
                <f eval2>
                    settitle ("Delivery interval");
                    status.is_filled = glocal.interval != -1;
                </f>
                <f dialog2>
                    if (glocal.interval == -1) glocal.interval = 15;
                    static int vals[]={
                        0,
                        15
                    };
                    static const char *options[]={
                        "disabled",
                        "default",
                        NULL
                    };
                    dia.newf_chkm_num ("Interval (minutes)",glocal.interval
                        ,15,vals,options);
                    edit();
                </f>
            </call>
            // We must write it back here
        }
        </mod>
        
        <mod>
        static void samples_combine ()
        {
            <call gurumanage>("combine"
                ,"We are combining the same simple guru twice.\n"
                 "This shows how code for one configuration may be connected\n"
                 "to provide a larger one.",help_nil);
                <f exec>
                    <call gurupath>(mode,status);
                        <f eval>
                            settitle ("Combining");
                        </f>
                        <f dialog>
                            setintro ("We are configuring SMTP twice");
                            edit();
                        </f>
                        <f path1>
                            samples_config_smtp(mode,status);
                        </f>
                        <f path2>
                            // Ok, we are reusing the same code above
                            // This is just a demo after all
                            samples_config_smtp(mode,status);
                        </f>
                    </call>
                </f>
            </call>
        }
        </mod>

Next Previous Contents