summaryrefslogtreecommitdiff
path: root/pith/osdep/collate.c
blob: 1481d28080874cf90d65b553dd8a3e7a59ddfc57 (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
157
158
159
160
161
162
163
164
165
166
167
/*
 * ========================================================================
 * Copyright 2013-2022 Eduardo Chappa
 * Copyright 2006 University of Washington
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * ========================================================================
 */

#include <system.h>

#include "collate.h"


/*
 * global hook 
 */
int (*pcollator)(const char *, const char *);


void
set_collation(int collation, int ctype)
{
    extern int collator(const char *, const char *);  /* set to strcoll if available in system.h */

    pcollator = strucmp;

#ifdef LC_COLLATE
  if(collation){
      char *status = NULL;

    /*
     * This may not have the desired effect, if collator is not
     * defined to be strcoll in os.h and strcmp and friends
     * don't know about locales. If your system does have strcoll
     * but we haven't defined collator to be strcoll in os.h, let us know.
     */
    status = setlocale(LC_COLLATE, "");

    /*
     * If there is an error or if the locale is the "C" locale, then we
     * don't want to use strcoll because in the default "C" locale strcoll
     * uses strcmp ordering and we want strucmp ordering.
     *
     * The problem with this is that setlocale returns a string which is
     * not equal to "C" on some systems even when the locale is "C", so we
     * can't really tell on those systems. On some systems like that, we
     * may end up with a strcmp-style collation instead of a strucmp-style.
     * We recommend that the users of those systems explicitly set
     * LC_COLLATE in their environment.
     */
    if(status && !(status[0] == 'C' && status[1] == '\0'))
      pcollator = collator;
  }
#endif
#ifdef LC_CTYPE
  if(ctype){
    (void)setlocale(LC_CTYPE, "");
  }
#endif

#ifdef LC_TIME
  setlocale(LC_TIME, "");
#endif
}


/*
 * sstrcasecmp - compare two pointers to strings case independently
 */
int
sstrcasecmp(const qsort_t *s1, const qsort_t *s2)
{
    return((*pcollator)(*(char **)s1, *(char **)s2));
}


#ifndef	_WINDOWS

/*--------------------------------------------------
     A case insensitive strcmp()     
  
   Args: o, r -- The two strings to compare

 Result: integer indicating which is greater
  ---*/
int
strucmp(const char *o, const char *r)
{
    if(o == NULL){
	if(r == NULL)
	  return 0;
	else
	  return -1;
    }
    else if(r == NULL)
      return 1;

    while(*o && *r
	  && ((isupper((unsigned char)(*o))
				  ? (unsigned char)tolower((unsigned char)(*o))
				  : (unsigned char)(*o))
	     == (isupper((unsigned char)(*r))
				  ? (unsigned char)tolower((unsigned char)(*r))
				  : (unsigned char)(*r)))){
	o++;
	r++;
    }

    return((isupper((unsigned char)(*o))
				? tolower((unsigned char)(*o))
				: (int)(unsigned char)(*o))
	   - (isupper((unsigned char)(*r))
			        ? tolower((unsigned char)(*r))
				: (int)(unsigned char)(*r)));
}

/*----------------------------------------------------------------------
     A case insensitive strncmp()     
  
   Args: o, r -- The two strings to compare
         n    -- length to stop comparing strings at

 Result: integer indicating which is greater
   
  ----*/
int
struncmp(const char *o, const char *r, int n)
{
    if(n < 1)
      return 0;

    if(o == NULL){
	if(r == NULL)
	  return 0;
	else
	  return -1;
    }
    else if(r == NULL)
      return 1;

    n--;
    while(n && *o && *r
	  && ((isupper((unsigned char)(*o))
				  ? (unsigned char)tolower((unsigned char)(*o))
				  : (unsigned char)(*o))
	     == (isupper((unsigned char)(*r))
				  ? (unsigned char)tolower((unsigned char)(*r))
				  : (unsigned char)(*r)))){
	o++;
	r++;
	n--;
    }

    return((isupper((unsigned char)(*o))
				? tolower((unsigned char)(*o))
				: (int)(unsigned char)(*o))
	   - (isupper((unsigned char)(*r))
			        ? tolower((unsigned char)(*r))
				: (int)(unsigned char)(*r)));
}
#endif