2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2007 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 /*======================================================================
17 display format/support routines
20 #include "../c-client/c-client.h"
33 #include "osdep/collate.h"
36 /* internal prototypes */
37 void parse_format(char *, COL_S
*);
43 * We have to call this to set up the format of the columns. There is a
44 * separate format for each addrbook, so we need to call this for each
45 * addrbook. We call it when the pab's are built. It also depends on
46 * whether or not as.checkboxes is set, so if we go into a Select mode
47 * from the address book maintenance screen we need to re-call this. Since
48 * we can't go back out of ListMode we don't have that problem. Restore_state
49 * has to call it because of the as.checkboxes possibly being different in
53 addrbook_new_disp_form(PerAddrBook
*pab
, char **list
, int addrbook_num
,
54 int (*prefix_f
)(PerAddrBook
*, int *))
59 dprint((9, "- init_disp_form(%s) -\n",
60 (pab
&& pab
->abnick
) ? pab
->abnick
: "?"));
62 memset((void *)pab
->disp_form
, 0, NFIELDS
*sizeof(COL_S
));
63 pab
->disp_form
[1].wtype
= WeCalculate
; /* so we don't get false AllAuto */
66 as
.do_bold
= (*prefix_f
)(pab
, &column
);
68 /* if custom format is specified */
69 if(list
&& list
[0] && list
[0][0]){
70 /* find the one for addrbook_num */
72 *list
!= NULL
&& addrbook_num
;
73 addrbook_num
--,list
++)
76 /* If not enough to go around, last one repeats */
78 parse_format(last_one
, &(pab
->disp_form
[column
]));
80 parse_format(*list
, &(pab
->disp_form
[column
]));
83 /* If 2nd wtype is AllAuto, the widths are calculated old way */
84 pab
->disp_form
[1].wtype
= AllAuto
;
86 pab
->disp_form
[column
++].type
= Nickname
;
87 pab
->disp_form
[column
++].type
= Fullname
;
88 pab
->disp_form
[column
++].type
= Addr
;
90 while(column
< NFIELDS
)
91 pab
->disp_form
[column
++].type
= Notused
;
101 struct parse_tokens ptokens
[] = {
102 {"NICKNAME", Nickname
},
103 {"FULLNAME", Fullname
},
106 {"COMMENT", Comment
},
112 * Parse format_str and fill in disp_form structure based on what's there.
114 * Args: format_str -- The format string from pinerc.
115 * disp_form -- This is where we fill in the answer.
117 * The format string consists of special tokens which give the order of
118 * the columns to be displayed. The possible tokens are NICKNAME,
119 * FULLNAME, ADDRESS, FCC, COMMENT. If a token is followed by
120 * parens with an integer inside (FULLNAME(16)) then that means we
121 * make that variable that many characters wide. If it is a percentage, we
122 * allocate that percentage of the columns to that variable. If no
123 * parens, that means we calculate it for the user. The tokens are
124 * delimited by white space. A token of DEFAULT means to calculate the
125 * whole thing as we would if no spec was given. This makes it possible
126 * to specify default for one addrbook and something special for another.
129 parse_format(char *format_str
, COL_S
*disp_form
)
133 struct parse_tokens
*pt
;
134 int nicknames
, fullnames
, addresses
, not_allauto
;
138 while(p
&& *p
&& column
< NFIELDS
){
139 p
= skip_white_space(p
); /* space for next word */
141 /* look for the ptoken this word matches */
142 for(pt
= ptokens
; pt
->name
; pt
++)
143 if(!struncmp(pt
->name
, p
, strlen(pt
->name
)))
146 /* ignore unrecognized word */
150 if((r
=strindex(p
, SPACE
)) != NULL
)
153 dprint((2, "parse_format: ignoring unrecognized word \"%s\" in address-book-formats\n", p
? p
: "?"));
154 q_status_message1(SM_ORDER
, warnings
++==0 ? 1 : 0, 4,
155 /* TRANSLATORS: an informative error message */
156 _("Ignoring unrecognized word \"%s\" in Address-Book-Formats"), p
);
161 /* skip unrecognized word */
162 while(p
&& *p
&& !isspace((unsigned char)(*p
)))
168 disp_form
[column
].type
= pt
->ctype
;
170 /* skip over name and look for parens */
171 p
+= strlen(pt
->name
);
175 while(p
&& *p
&& isdigit((unsigned char)*p
))
178 if(p
&& *p
&& *p
== ')' && p
> q
){
179 disp_form
[column
].wtype
= Fixed
;
180 disp_form
[column
].req_width
= atoi(q
);
182 else if(p
&& *p
&& *p
== '%' && p
> q
){
183 disp_form
[column
].wtype
= Percent
;
184 disp_form
[column
].req_width
= atoi(q
);
187 disp_form
[column
].wtype
= WeCalculate
;
188 if(disp_form
[column
].type
== Nickname
)
189 disp_form
[column
].req_width
= 8;
191 disp_form
[column
].req_width
= 3;
195 disp_form
[column
].wtype
= WeCalculate
;
196 if(disp_form
[column
].type
== Nickname
)
197 disp_form
[column
].req_width
= 8;
199 disp_form
[column
].req_width
= 3;
202 if(disp_form
[column
].type
== Def
){
203 /* If any type is DEFAULT, the widths are calculated old way */
207 disp_form
[column
].wtype
= AllAuto
;
208 disp_form
[column
++].type
= Nickname
;
209 disp_form
[column
].wtype
= AllAuto
;
210 disp_form
[column
++].type
= Fullname
;
211 disp_form
[column
].wtype
= AllAuto
;
212 disp_form
[column
++].type
= Addr
;
214 while(column
< NFIELDS
)
215 disp_form
[column
++].type
= Notused
;
221 /* skip text at end of word */
222 while(p
&& *p
&& !isspace((unsigned char)(*p
)))
227 q_status_message(SM_ORDER
, 0, 4,
228 _("Address-Book-Formats has no recognizable words, using default format"));
233 while(column
< NFIELDS
)
234 disp_form
[column
++].type
= Notused
;
236 /* check to see if user is just re-ordering default fields */
241 for(column
= 0; column
< NFIELDS
; column
++){
242 if(disp_form
[column
].type
!= Notused
243 && disp_form
[column
].wtype
!= WeCalculate
)
246 switch(disp_form
[column
].type
){
270 * Special case: if there is no address field specified, we put in
271 * a special field called WhenNoAddrDisplayed, which causes list
272 * entries to be displayable in all cases.
275 for(column
= 0; column
< NFIELDS
; column
++)
276 if(disp_form
[column
].type
== Notused
)
279 if(column
< NFIELDS
){
280 disp_form
[column
].type
= WhenNoAddrDisplayed
;
281 disp_form
[column
].wtype
= Special
;
285 if(nicknames
== 1 && fullnames
== 1 && addresses
== 1 && not_allauto
== 0)
286 disp_form
[0].wtype
= AllAuto
; /* set to do default widths */
291 * Find the first selectable line greater than or equal to line. That is,
292 * the first line the cursor is allowed to start on.
293 * (If there are none >= line, it will find the highest one.)
295 * Returns the line number of the found line or NO_LINE if there isn't one.
298 first_selectable_line(long int line
)
301 register PerAddrBook
*pab
;
304 /* skip past non-selectable lines */
306 !line_is_selectable(lineno
) && dlist(lineno
)->type
!= End
;
310 if(line_is_selectable(lineno
))
314 * There were no selectable lines from lineno on down. Trying looking
318 !line_is_selectable(lineno
) && dlist(lineno
)->type
!= Beginning
;
322 if(line_is_selectable(lineno
))
326 * No selectable lines at all.
327 * If some of the addrbooks are still not displayed, it is too
328 * early to set the no_op_possbl flag. Or, if some of the addrbooks
329 * are empty but writable, then we should not set it either.
331 for(i
= 0; i
< as
.n_addrbk
; i
++){
333 if(pab
->ostatus
!= Open
&&
334 pab
->ostatus
!= HalfOpen
&&
335 pab
->ostatus
!= ThreeQuartOpen
)
338 if(pab
->access
== ReadWrite
&& adrbk_count(pab
->address_book
) == 0)
348 * Returns 1 if this line is of a type that can have a cursor on it.
351 line_is_selectable(long int lineno
)
353 register AddrScrn_Disp
*dl
;
355 if((dl
= dlist(lineno
)) && (dl
->type
== Text
||
356 dl
->type
== ListEmpty
||
357 dl
->type
== TitleCmb
||
358 dl
->type
== Beginning
||