summaryrefslogtreecommitdiff
path: root/agen5/expGperf.c
blob: 902f18b7543fbc5676f29ddaa44d91cb986de3d1 (plain)
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
 * @file expGperf.c
 *
 *  Time-stamp:        "2012-01-15 08:38:23 bkorb"
 *
 *  Create a perfect hash function program and use it to compute
 *  index values for a list of provided names.  It also documents how
 *  to incorporate that hashing function into a generated C program.
 *
 *  This file is part of AutoGen.
 *  Copyright (c) 1992-2012 Bruce Korb - all rights reserved
 *
 * AutoGen is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * AutoGen is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef SHELL_ENABLED
HIDE_FN(SCM ag_scm_make_gperf(SCM name, SCM hlist))
{
    return SCM_UNDEFINED;
}

HIDE_FN(SCM ag_scm_gperf(SCM name, SCM str))
{
    return SCM_UNDEFINED;
}
#else

/*=gfunc make_gperf
 *
 * what:   build a perfect hash function program
 * general_use:
 *
 * exparg: name , name of hash list
 * exparg: strings , list of strings to hash ,, list
 *
 * doc:  Build a program to perform perfect hashes of a known list of input
 *       strings.  This function produces no output, but prepares a program
 *       named, @file{gperf_<name>} for use by the gperf function
 *       @xref{SCM gperf}.
 *
 *       This program will be obliterated as AutoGen exits.
 *       However, you may incorporate the generated hashing function
 *       into your C program with commands something like the following:
 *
 *       @example
 *       [+ (shellf "sed '/^int main(/,$d;/^#line/d' $@{gpdir@}/%s.c"
 *                  name ) +]
 *       @end example
 *
 *       where @code{name} matches the name provided to this @code{make-perf}
 *       function.  @code{gpdir} is the variable used to store the name of the
 *       temporary directory used to stash all the files.
=*/
SCM
ag_scm_make_gperf(SCM name, SCM hlist)
{
    static bool do_cleanup = true;

    char const * pzName  = ag_scm2zchars(name, "gperf name");
    char const * pzList;
    SCM          newline = AG_SCM_STR2SCM(NEWLINE, (size_t)1);

    if (! AG_SCM_STRING_P(name))
        return SCM_UNDEFINED;

    /*
     *  Construct the newline separated list of values
     */
    hlist  = ag_scm_join(newline, hlist);
    pzList = ag_scm2zchars(hlist, "hash list");

    /*
     *  Stash the concatenated list somewhere, hopefully without an alloc.
     */
    {
        char * cmd = aprf(MK_GPERF_SCRIPT, zMakeProg, pzName, pzList);

        /*
         *  Run the command and ignore the results.
         *  In theory, the program should be ready.
         */
        pzList = shell_cmd(cmd);
        AGFREE(cmd);

        if (pzList != NULL)
            free((void *)pzList);
    }

    if (do_cleanup) {
        SCM_EVAL_CONST(MAKE_GPERF_CLEANUP);
        do_cleanup = false;
    }

    return SCM_BOOL_T;
}


/*=gfunc gperf
 *
 * what:   perform a perfect hash function
 * general_use:
 *
 * exparg: name , name of hash list
 * exparg: str  , string to hash
 *
 * doc:  Perform the perfect hash on the input string.  This is only useful if
 *       you have previously created a gperf program with the @code{make-gperf}
 *       function @xref{SCM make-gperf}.  The @code{name} you supply here must
 *       match the name used to create the program and the string to hash must
 *       be one of the strings supplied in the @code{make-gperf} string list.
 *       The result will be a perfect hash index.
 *
 *       See the documentation for @command{gperf(1GNU)} for more details.
=*/
SCM
ag_scm_gperf(SCM name, SCM str)
{
    char const * cmd;
    char const * key2hash = ag_scm2zchars(str,  "key-to-hash");
    char const * gp_name  = ag_scm2zchars(name, "gperf name");

    /*
     *  Format the gperf command and check the result.  If it fits in
     *  scribble space, use that.
     *  (If it does fit, then the test string fits already).
     */
    cmd = aprf(RUN_GPERF_CMD, gp_name, key2hash);
    key2hash = shell_cmd(cmd);
    if (*key2hash == NUL)
        str = SCM_UNDEFINED;
    else
        str = AG_SCM_STR02SCM(key2hash);

    AGFREE((void *)cmd);
    AGFREE((void *)key2hash);
    return str;
}
#endif
/*
 * Local Variables:
 * mode: C
 * c-file-style: "stroustrup"
 * indent-tabs-mode: nil
 * End:
 * end of agen5/expGperf.c */